From a10204d62123cc7bba92dc518e3b9a251a1d7323 Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 30 Jun 2024 11:33:50 +0300 Subject: [PATCH 01/82] Refactor commands output formats --- {formats => utils/formats}/conversion.go | 0 {formats => utils/formats}/simplejsonapi.go | 0 {formats => utils/formats}/summary.go | 0 {formats => utils/formats}/summary_test.go | 0 {formats => utils/formats}/table.go | 0 utils/results/common.go | 604 ++++++++++++++++++++ utils/resultstable.go | 78 --- utils/techutils/techutils.go | 80 +++ 8 files changed, 684 insertions(+), 78 deletions(-) rename {formats => utils/formats}/conversion.go (100%) rename {formats => utils/formats}/simplejsonapi.go (100%) rename {formats => utils/formats}/summary.go (100%) rename {formats => utils/formats}/summary_test.go (100%) rename {formats => utils/formats}/table.go (100%) create mode 100644 utils/results/common.go diff --git a/formats/conversion.go b/utils/formats/conversion.go similarity index 100% rename from formats/conversion.go rename to utils/formats/conversion.go diff --git a/formats/simplejsonapi.go b/utils/formats/simplejsonapi.go similarity index 100% rename from formats/simplejsonapi.go rename to utils/formats/simplejsonapi.go diff --git a/formats/summary.go b/utils/formats/summary.go similarity index 100% rename from formats/summary.go rename to utils/formats/summary.go diff --git a/formats/summary_test.go b/utils/formats/summary_test.go similarity index 100% rename from formats/summary_test.go rename to utils/formats/summary_test.go diff --git a/formats/table.go b/utils/formats/table.go similarity index 100% rename from formats/table.go rename to utils/formats/table.go diff --git a/utils/results/common.go b/utils/results/common.go new file mode 100644 index 00000000..0dbb4ac8 --- /dev/null +++ b/utils/results/common.go @@ -0,0 +1,604 @@ +package results + +import ( + "fmt" + "path/filepath" + "strconv" + "strings" + + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/severityutils" + "github.com/jfrog/jfrog-cli-security/utils/techutils" + "github.com/jfrog/jfrog-client-go/utils/errorutils" + "github.com/jfrog/jfrog-client-go/utils/log" + "github.com/jfrog/jfrog-client-go/xray/services" + "github.com/owenrumney/go-sarif/v2/sarif" + "golang.org/x/exp/slices" +) + +const ( + customLicenseViolationId = "custom_license_violation" + rootIndex = 0 + directDependencyIndex = 1 + directDependencyPathLength = 2 + nodeModules = "node_modules" + NpmPackageTypeIdentifier = "npm://" +) + +var ( + ConvertorResetErr = fmt.Errorf("Reset must be called before parsing new scan results metadata") + ConvertorNewScanErr = fmt.Errorf("ParseNewScanResultsMetadata must be called before starting to parse issues") +) + +func NewFailBuildError() error { + return coreutils.CliError{ExitCode: coreutils.ExitCodeVulnerableBuild, ErrorMsg: "One or more of the violations found are set to fail builds that include them"} +} + +// In case one (or more) of the violations contains the field FailBuild set to true, CliError with exit code 3 will be returned. +func CheckIfFailBuild(results []services.ScanResponse) bool { + for _, result := range results { + for _, violation := range result.Violations { + if violation.FailBuild { + return true + } + } + } + return false +} + +type PrepareScaVulnerabilityFunc func(vulnerability services.Vulnerability, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error +type PrepareScaViolationFunc func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error +type PrepareLicensesFunc func(license services.License, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error +type PrepareJasFunc func(run *sarif.Run, rule *sarif.ReportingDescriptor, severity severityutils.Severity, result *sarif.Result, location *sarif.Location) error + +func PrepareJasIssues(target string, runs []*sarif.Run, entitledForJas bool, handler PrepareJasFunc) error { + if !entitledForJas || handler == nil { + return nil + } + for _, run := range runs { + for _, result := range run.Results { + severity, err := severityutils.ParseSeverity(sarifutils.GetResultLevel(result), true) + if err != nil { + return err + } + rule, err := run.GetRuleById(*result.RuleID) + if errorutils.CheckError(err) != nil { + return err + } + if len(result.Locations) == 0 { + // If there are no locations, the issue is not specific to a location, and we should handle it as a general issue. + if err := handler(run, rule, severity, result, nil); err != nil { + return err + } + } else { + for _, location := range result.Locations { + if err := handler(run, rule, severity, result, location); err != nil { + return err + } + } + } + } + } + return nil +} + +func PrepareScaVulnerabilities(target string, vulnerabilities []services.Vulnerability, pretty, entitledForJas bool, applicabilityRuns []*sarif.Run, handler PrepareScaVulnerabilityFunc) error { + if handler == nil { + return nil + } + for _, vulnerability := range vulnerabilities { + impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, fixedVersions, directComponents, impactPaths, err := SplitComponents(target, vulnerability.Components) + if err != nil { + return err + } + cves, applicabilityStatus := ConvertCvesWithApplicability(vulnerability.Cves, entitledForJas, applicabilityRuns, vulnerability.Components) + severity, err := severityutils.ParseSeverity(vulnerability.Severity, false) + if err != nil { + return err + } + for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { + if err := handler( + vulnerability, cves, applicabilityStatus, severity, + impactedPackagesNames[compIndex], impactedPackagesVersions[compIndex], impactedPackagesTypes[compIndex], + fixedVersions[compIndex], directComponents[compIndex], impactPaths[compIndex], + ); err != nil { + return err + } + } + } + return nil +} + +func PrepareScaViolations(target string, violations []services.Violation, pretty, entitledForJas bool, applicabilityRuns []*sarif.Run, securityHandler PrepareScaViolationFunc, licenseHandler PrepareScaViolationFunc, operationalRiskHandler PrepareScaViolationFunc) error { + for _, violation := range violations { + impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, fixedVersions, directComponents, impactPaths, err := SplitComponents(target, violation.Components) + if err != nil { + return err + } + cves, applicabilityStatus := ConvertCvesWithApplicability(violation.Cves, entitledForJas, applicabilityRuns, violation.Components) + severity, err := severityutils.ParseSeverity(violation.Severity, false) + if err != nil { + return err + } + switch violation.ViolationType { + case formats.ViolationTypeSecurity.String(): + if securityHandler == nil { + continue + } + for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { + if err := securityHandler( + violation, cves, applicabilityStatus, severity, + impactedPackagesNames[compIndex], impactedPackagesVersions[compIndex], impactedPackagesTypes[compIndex], + fixedVersions[compIndex], directComponents[compIndex], impactPaths[compIndex], + ); err != nil { + return err + } + } + case formats.ViolationTypeLicense.String(): + if licenseHandler == nil { + continue + } + for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { + if err := licenseHandler( + violation, cves, applicabilityStatus, severity, + impactedPackagesNames[compIndex], impactedPackagesVersions[compIndex], impactedPackagesTypes[compIndex], + fixedVersions[compIndex], directComponents[compIndex], impactPaths[compIndex], + ); err != nil { + return err + } + } + case formats.ViolationTypeOperationalRisk.String(): + if operationalRiskHandler == nil { + continue + } + for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { + if err := operationalRiskHandler( + violation, cves, applicabilityStatus, severity, + impactedPackagesNames[compIndex], impactedPackagesVersions[compIndex], impactedPackagesTypes[compIndex], + fixedVersions[compIndex], directComponents[compIndex], impactPaths[compIndex], + ); err != nil { + return err + } + } + } + } + return nil +} + +func PrepareLicenses(target string, licenses []services.License, handler PrepareLicensesFunc) error { + if handler == nil { + return nil + } + for _, license := range licenses { + impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, _, directComponents, impactPaths, err := SplitComponents(target, license.Components) + if err != nil { + return err + } + for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { + if err := handler( + license, impactedPackagesNames[compIndex], impactedPackagesVersions[compIndex], impactedPackagesTypes[compIndex], directComponents[compIndex], impactPaths[compIndex], + ); err != nil { + return err + } + } + } + return nil +} + +func SplitComponents(target string, impactedPackages map[string]services.Component) (impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes []string, fixedVersions [][]string, directComponents [][]formats.ComponentRow, impactPaths [][][]formats.ComponentRow, err error) { + if len(impactedPackages) == 0 { + err = errorutils.CheckErrorf("failed while parsing the response from Xray: violation doesn't have any components") + return + } + for currCompId, currComp := range impactedPackages { + currCompName, currCompVersion, currCompType := techutils.SplitComponentId(currCompId) + impactedPackagesNames = append(impactedPackagesNames, currCompName) + impactedPackagesVersions = append(impactedPackagesVersions, currCompVersion) + impactedPackagesTypes = append(impactedPackagesTypes, currCompType) + fixedVersions = append(fixedVersions, currComp.FixedVersions) + currDirectComponents, currImpactPaths := getDirectComponentsAndImpactPaths(target, currComp.ImpactPaths) + directComponents = append(directComponents, currDirectComponents) + impactPaths = append(impactPaths, currImpactPaths) + } + return +} + +// Gets a slice of the direct dependencies or packages of the scanned component, that depends on the vulnerable package, and converts the impact paths. +func getDirectComponentsAndImpactPaths(target string, impactPaths [][]services.ImpactPathNode) (components []formats.ComponentRow, impactPathsRows [][]formats.ComponentRow) { + componentsMap := make(map[string]formats.ComponentRow) + + // The first node in the impact path is the scanned component itself. The second one is the direct dependency. + impactPathLevel := 1 + for _, impactPath := range impactPaths { + impactPathIndex := impactPathLevel + if len(impactPath) <= impactPathLevel { + impactPathIndex = len(impactPath) - 1 + } + componentId := impactPath[impactPathIndex].ComponentId + if _, exist := componentsMap[componentId]; !exist { + compName, compVersion, _ := techutils.SplitComponentId(componentId) + componentsMap[componentId] = formats.ComponentRow{Name: compName, Version: compVersion, Location: getComponentLocation(target)} + } + + // Convert the impact path + var compImpactPathRows []formats.ComponentRow + for _, pathNode := range impactPath { + nodeCompName, nodeCompVersion, _ := techutils.SplitComponentId(pathNode.ComponentId) + compImpactPathRows = append(compImpactPathRows, formats.ComponentRow{ + Name: nodeCompName, + Version: nodeCompVersion, + }) + } + impactPathsRows = append(impactPathsRows, compImpactPathRows) + } + + for _, row := range componentsMap { + components = append(components, row) + } + return +} + +func getComponentLocation(target string) *formats.Location { + if target == "" { + return nil + } + return &formats.Location{File: target} +} + +func GetIssueIdentifier(cvesRow []formats.CveRow, issueId string, delimiter string) string { + var cvesBuilder strings.Builder + for i, cve := range cvesRow { + if i > 0 { + cvesBuilder.WriteString(delimiter) + } + cvesBuilder.WriteString(cve.Id) + } + identifier := cvesBuilder.String() + if identifier == "" { + identifier = issueId + } + return identifier +} + +func GetScaIssueId(depName, version, issueId string) string { + return fmt.Sprintf("%s_%s_%s", issueId, depName, version) +} + +func ConvertCvesWithApplicability(cves []services.Cve, entitledForJas bool, applicabilityRuns []*sarif.Run, components map[string]services.Component) (convertedCves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus) { + convertedCves = convertCves(cves) + applicabilityStatus = jasutils.ApplicabilityUndetermined + if entitledForJas { + for i := range convertedCves { + convertedCves[i].Applicability = GetCveApplicabilityField(convertedCves[i].Id, applicabilityRuns, components) + } + applicabilityStatus = GetApplicableCveStatus(entitledForJas, applicabilityRuns, convertedCves) + } + return +} + +func convertCves(cves []services.Cve) []formats.CveRow { + var cveRows []formats.CveRow + for _, cveObj := range cves { + cveRows = append(cveRows, formats.CveRow{Id: cveObj.Id, CvssV2: cveObj.CvssV2Score, CvssV3: cveObj.CvssV3Score}) + } + return cveRows +} + +// FindMaxCVEScore returns the maximum CVSS score of the given CVEs or score based on severity and applicability status if not exists. +func FindMaxCVEScore(severity severityutils.Severity, applicabilityStatus jasutils.ApplicabilityStatus, cves []formats.CveRow) (string, error) { + maxCve := severityutils.MinCveScore + for _, cve := range cves { + cveScore, err := GetCveScore(severity, applicabilityStatus, cve) + if err != nil { + return "", err + } + if cveScore > maxCve { + maxCve = cveScore + } + // if found maximum possible cve score, no need to keep iterating + if maxCve == severityutils.MaxCveScore { + break + } + } + return fmt.Sprintf("%.1f", maxCve), nil +} + +// GetCveScore returns the CVSS score of the given CVE or score based on severity and applicability status if not exists. +func GetCveScore(severity severityutils.Severity, applicabilityStatus jasutils.ApplicabilityStatus, cve formats.CveRow) (float32, error) { + if cve.CvssV3 == "" { + return severityutils.GetSeverityScore(severity, applicabilityStatus), nil + } + score, err := strconv.ParseFloat(cve.CvssV3, 32) + return float32(score), err +} + +func GetViolatedLicenses(allowedLicenses []string, licenses []services.License) (violatedLicenses []services.Violation) { + if len(allowedLicenses) == 0 { + return + } + for _, license := range licenses { + if !slices.Contains(allowedLicenses, license.Key) { + violatedLicenses = append(violatedLicenses, services.Violation{ + LicenseKey: license.Key, + LicenseName: license.Name, + Severity: severityutils.Medium.String(), + Components: license.Components, + IssueId: customLicenseViolationId, + WatchName: fmt.Sprintf("jfrog_%s", customLicenseViolationId), + ViolationType: formats.ViolationTypeLicense.String(), + }) + } + } + return +} + +// appendUniqueImpactPathsForMultipleRoots appends the source impact path to the target impact path while avoiding duplicates. +// Specifically, it is designed for handling multiple root projects, such as Maven or Gradle, by comparing each pair of paths and identifying the path that is closest to the direct dependency. +func AppendUniqueImpactPathsForMultipleRoots(target [][]services.ImpactPathNode, source [][]services.ImpactPathNode) [][]services.ImpactPathNode { + for targetPathIndex, targetPath := range target { + for sourcePathIndex, sourcePath := range source { + var subset []services.ImpactPathNode + if len(sourcePath) <= len(targetPath) { + subset = isImpactPathIsSubset(targetPath, sourcePath) + if len(subset) != 0 { + target[targetPathIndex] = subset + } + } else { + subset = isImpactPathIsSubset(sourcePath, targetPath) + if len(subset) != 0 { + source[sourcePathIndex] = subset + } + } + } + } + + return AppendUniqueImpactPaths(target, source, false) +} + +// isImpactPathIsSubset checks if targetPath is a subset of sourcePath, and returns the subset if exists +func isImpactPathIsSubset(target []services.ImpactPathNode, source []services.ImpactPathNode) []services.ImpactPathNode { + var subsetImpactPath []services.ImpactPathNode + impactPathNodesMap := make(map[string]bool) + for _, node := range target { + impactPathNodesMap[node.ComponentId] = true + } + + for _, node := range source { + if impactPathNodesMap[node.ComponentId] { + subsetImpactPath = append(subsetImpactPath, node) + } + } + + if len(subsetImpactPath) == len(target) || len(subsetImpactPath) == len(source) { + return subsetImpactPath + } + return []services.ImpactPathNode{} +} + +// appendImpactPathsWithoutDuplicates appends the elements of a source [][]ImpactPathNode struct to a target [][]ImpactPathNode, without adding any duplicate elements. +// This implementation uses the ComponentId field of the ImpactPathNode struct to check for duplicates, as it is guaranteed to be unique. +func AppendUniqueImpactPaths(target [][]services.ImpactPathNode, source [][]services.ImpactPathNode, multipleRoots bool) [][]services.ImpactPathNode { + if multipleRoots { + return AppendUniqueImpactPathsForMultipleRoots(target, source) + } + impactPathMap := make(map[string][]services.ImpactPathNode) + for _, path := range target { + // The first node component id is the key and the value is the whole path + key := getImpactPathKey(path) + impactPathMap[key] = path + } + + for _, path := range source { + key := getImpactPathKey(path) + if _, exists := impactPathMap[key]; !exists { + impactPathMap[key] = path + target = append(target, path) + } + } + return target +} + +// getImpactPathKey return a key that is used as a key to identify and deduplicate impact paths. +// If an impact path length is equal to directDependencyPathLength, then the direct dependency is the key, and it's in the directDependencyIndex place. +func getImpactPathKey(path []services.ImpactPathNode) string { + key := path[rootIndex].ComponentId + if len(path) == directDependencyPathLength { + key = path[directDependencyIndex].ComponentId + } + return key +} + +func SplitScaScanResults(results *ScanCommandResults) ([]services.Violation, []services.Vulnerability, []services.License) { + var violations []services.Violation + var vulnerabilities []services.Vulnerability + var licenses []services.License + for _, scan := range results.Scans { + for _, scaScan := range scan.ScaResults { + violations = append(violations, scaScan.XrayResult.Violations...) + vulnerabilities = append(vulnerabilities, scaScan.XrayResult.Vulnerabilities...) + licenses = append(licenses, scaScan.XrayResult.Licenses...) + } + } + return violations, vulnerabilities, licenses +} + +func GetCveApplicabilityField(cveId string, applicabilityScanResults []*sarif.Run, components map[string]services.Component) *formats.Applicability { + if len(applicabilityScanResults) == 0 { + return nil + } + applicability := formats.Applicability{} + resultFound := false + var applicabilityStatuses []jasutils.ApplicabilityStatus + for _, applicabilityRun := range applicabilityScanResults { + if rule, _ := applicabilityRun.GetRuleById(jasutils.CveToApplicabilityRuleId(cveId)); rule != nil { + applicability.ScannerDescription = sarifutils.GetRuleFullDescription(rule) + status := getApplicabilityStatusFromRule(rule) + if status != "" { + applicabilityStatuses = append(applicabilityStatuses, status) + } + } + result, _ := applicabilityRun.GetResultByRuleId(jasutils.CveToApplicabilityRuleId(cveId)) + if result == nil { + continue + } + resultFound = true + // Add new evidences from locations + for _, location := range result.Locations { + fileName := sarifutils.GetRelativeLocationFileName(location, applicabilityRun.Invocations) + // TODO: maybe, move this logic to the convertor + if shouldDisqualifyEvidence(components, fileName) { + continue + } + applicability.Evidence = append(applicability.Evidence, formats.Evidence{ + Location: formats.Location{ + File: fileName, + StartLine: sarifutils.GetLocationStartLine(location), + StartColumn: sarifutils.GetLocationStartColumn(location), + EndLine: sarifutils.GetLocationEndLine(location), + EndColumn: sarifutils.GetLocationEndColumn(location), + Snippet: sarifutils.GetLocationSnippet(location), + }, + Reason: sarifutils.GetResultMsgText(result), + }) + } + } + switch { + case len(applicabilityStatuses) > 0: + applicability.Status = string(getFinalApplicabilityStatus(applicabilityStatuses)) + case !resultFound: + applicability.Status = string(jasutils.ApplicabilityUndetermined) + case len(applicability.Evidence) == 0: + applicability.Status = string(jasutils.NotApplicable) + default: + applicability.Status = string(jasutils.Applicable) + } + return &applicability +} + +func GetApplicableCvesStatus(entitledForJas bool, applicabilityScanResults []*sarif.Run, cves ...services.Cve) jasutils.ApplicabilityStatus { + if !entitledForJas || len(applicabilityScanResults) == 0 { + return jasutils.NotScanned + } + if len(cves) == 0 { + return jasutils.NotCovered + } + var applicableStatuses []jasutils.ApplicabilityStatus + for _, cve := range cves { + for _, applicabilityRun := range applicabilityScanResults { + if rule, _ := applicabilityRun.GetRuleById(jasutils.CveToApplicabilityRuleId(cve.Id)); rule != nil { + status := getApplicabilityStatusFromRule(rule) + if status != "" { + applicableStatuses = append(applicableStatuses, status) + } + } + } + } + return getFinalApplicabilityStatus(applicableStatuses) + +} + +func GetApplicableCveStatus(entitledForJas bool, applicabilityScanResults []*sarif.Run, cves []formats.CveRow) jasutils.ApplicabilityStatus { + if !entitledForJas || len(applicabilityScanResults) == 0 { + return jasutils.NotScanned + } + if len(cves) == 0 { + return jasutils.NotCovered + } + var applicableStatuses []jasutils.ApplicabilityStatus + for _, cve := range cves { + if cve.Applicability != nil { + applicableStatuses = append(applicableStatuses, jasutils.ApplicabilityStatus(cve.Applicability.Status)) + } + } + return getFinalApplicabilityStatus(applicableStatuses) +} + +func getApplicabilityStatusFromRule(rule *sarif.ReportingDescriptor) jasutils.ApplicabilityStatus { + if rule.Properties["applicability"] != nil { + status, ok := rule.Properties["applicability"].(string) + if !ok { + log.Debug(fmt.Sprintf("Failed to get applicability status from rule properties for rule_id %s", rule.ID)) + } + switch status { + case "not_covered": + return jasutils.NotCovered + case "undetermined": + return jasutils.ApplicabilityUndetermined + case "not_applicable": + return jasutils.NotApplicable + case "applicable": + return jasutils.Applicable + } + } + return "" +} + +// Relevant only when "third-party-contextual-analysis" flag is on, +// which mean we scan the environment folders as well (node_modules for example...) +// When a certain package is reported applicable, and the evidence found +// is inside the source code of the same package, we should disqualify it. +// +// For example, +// Cve applicability was found inside the 'mquery' package. +// filePath = myProject/node_modules/mquery/badCode.js , disqualify = True. +// Disqualify the above evidence, as the reported applicability is used inside its own package. +// +// filePath = myProject/node_modules/mpath/badCode.js , disqualify = False. +// Found use of a badCode inside the node_modules from a different package, report applicable. +func shouldDisqualifyEvidence(components map[string]services.Component, evidenceFilePath string) (disqualify bool) { + for key := range components { + if !strings.HasPrefix(key, NpmPackageTypeIdentifier) { + return + } + dependencyName := extractDependencyNameFromComponent(key, NpmPackageTypeIdentifier) + // Check both Unix & Windows paths. + if strings.Contains(evidenceFilePath, nodeModules+"/"+dependencyName) || strings.Contains(evidenceFilePath, filepath.Join(nodeModules, dependencyName)) { + return true + } + } + return +} + +func extractDependencyNameFromComponent(key string, techIdentifier string) (dependencyName string) { + packageAndVersion := strings.TrimPrefix(key, techIdentifier) + split := strings.Split(packageAndVersion, ":") + if len(split) < 2 { + return + } + dependencyName = split[0] + return +} + +// If we don't get any statues it means the applicability scanner didn't run -> final value is not scanned +// If at least one cve is applicable -> final value is applicable +// Else if at least one cve is undetermined -> final value is undetermined +// Else if all cves are not covered -> final value is not covered +// Else (case when all cves aren't applicable) -> final value is not applicable +func getFinalApplicabilityStatus(applicabilityStatuses []jasutils.ApplicabilityStatus) jasutils.ApplicabilityStatus { + if len(applicabilityStatuses) == 0 { + return jasutils.NotScanned + } + foundUndetermined := false + foundNotCovered := false + for _, status := range applicabilityStatuses { + if status == jasutils.Applicable { + return jasutils.Applicable + } + if status == jasutils.ApplicabilityUndetermined { + foundUndetermined = true + } + if status == jasutils.NotCovered { + foundNotCovered = true + } + } + if foundUndetermined { + return jasutils.ApplicabilityUndetermined + } + if foundNotCovered { + return jasutils.NotCovered + } + return jasutils.NotApplicable +} \ No newline at end of file diff --git a/utils/resultstable.go b/utils/resultstable.go index a8f583f1..19ee9e44 100644 --- a/utils/resultstable.go +++ b/utils/resultstable.go @@ -517,85 +517,7 @@ func splitComponents(impactedPackages map[string]services.Component) (impactedPa return } -var packageTypes = map[string]string{ - "gav": "Maven", - "docker": "Docker", - "rpm": "RPM", - "deb": "Debian", - "nuget": "NuGet", - "generic": "Generic", - "npm": "npm", - "pip": "Python", - "pypi": "Python", - "composer": "Composer", - "go": "Go", - "alpine": "Alpine", -} - -// SplitComponentId splits a Xray component ID to the component name, version and package type. -// In case componentId doesn't contain a version, the returned version will be an empty string. -// In case componentId's format is invalid, it will be returned as the component name -// and empty strings will be returned instead of the version and the package type. -// Examples: -// 1. componentId: "gav://antparent:ant:1.6.5" -// Returned values: -// Component name: "antparent:ant" -// Component version: "1.6.5" -// Package type: "Maven" -// 2. componentId: "generic://sha256:244fd47e07d1004f0aed9c156aa09083c82bf8944eceb67c946ff7430510a77b/foo.jar" -// Returned values: -// Component name: "foo.jar" -// Component version: "" -// Package type: "Generic" -// 3. componentId: "invalid-comp-id" -// Returned values: -// Component name: "invalid-comp-id" -// Component version: "" -// Package type: "" -func SplitComponentId(componentId string) (string, string, string) { - compIdParts := strings.Split(componentId, "://") - // Invalid component ID - if len(compIdParts) != 2 { - return componentId, "", "" - } - - packageType := compIdParts[0] - packageId := compIdParts[1] - - // Generic identifier structure: generic://sha256:/name - if packageType == "generic" { - lastSlashIndex := strings.LastIndex(packageId, "/") - return packageId[lastSlashIndex+1:], "", packageTypes[packageType] - } - - var compName, compVersion string - switch packageType { - case "rpm": - // RPM identifier structure: rpm://os-version:package:epoch-version:version - // os-version is optional. - splitCompId := strings.Split(packageId, ":") - if len(splitCompId) >= 3 { - compName = splitCompId[len(splitCompId)-3] - compVersion = fmt.Sprintf("%s:%s", splitCompId[len(splitCompId)-2], splitCompId[len(splitCompId)-1]) - } - default: - // All other identifiers look like this: package-type://package-name:version. - // Sometimes there's a namespace or a group before the package name, separated by a '/' or a ':'. - lastColonIndex := strings.LastIndex(packageId, ":") - - if lastColonIndex != -1 { - compName = packageId[:lastColonIndex] - compVersion = packageId[lastColonIndex+1:] - } - } - // If there's an error while parsing the component ID - if compName == "" { - compName = packageId - } - - return compName, compVersion, packageTypes[packageType] -} // Gets a slice of the direct dependencies or packages of the scanned component, that depends on the vulnerable package, and converts the impact paths. func getDirectComponentsAndImpactPaths(impactPaths [][]services.ImpactPathNode) (components []formats.ComponentRow, impactPathsRows [][]formats.ComponentRow) { diff --git a/utils/techutils/techutils.go b/utils/techutils/techutils.go index 8d86abd6..7c2d69be 100644 --- a/utils/techutils/techutils.go +++ b/utils/techutils/techutils.go @@ -49,6 +49,21 @@ const ( CSharp CodeLanguage = "C#" ) +var packageTypes = map[string]string{ + "gav": "Maven", + "docker": "Docker", + "rpm": "RPM", + "deb": "Debian", + "nuget": "NuGet", + "generic": "Generic", + "npm": "npm", + "pip": "Python", + "pypi": "Python", + "composer": "Composer", + "go": "Go", + "alpine": "Alpine", +} + type TechData struct { // The name of the package type used in this technology. packageType string @@ -491,3 +506,68 @@ func GetAllTechnologiesList() (technologies []Technology) { } return } + +// SplitComponentId splits a Xray component ID to the component name, version and package type. +// In case componentId doesn't contain a version, the returned version will be an empty string. +// In case componentId's format is invalid, it will be returned as the component name +// and empty strings will be returned instead of the version and the package type. +// Examples: +// 1. componentId: "gav://antparent:ant:1.6.5" +// Returned values: +// Component name: "antparent:ant" +// Component version: "1.6.5" +// Package type: "Maven" +// 2. componentId: "generic://sha256:244fd47e07d1004f0aed9c156aa09083c82bf8944eceb67c946ff7430510a77b/foo.jar" +// Returned values: +// Component name: "foo.jar" +// Component version: "" +// Package type: "Generic" +// 3. componentId: "invalid-comp-id" +// Returned values: +// Component name: "invalid-comp-id" +// Component version: "" +// Package type: "" +func SplitComponentId(componentId string) (string, string, string) { + compIdParts := strings.Split(componentId, "://") + // Invalid component ID + if len(compIdParts) != 2 { + return componentId, "", "" + } + + packageType := compIdParts[0] + packageId := compIdParts[1] + + // Generic identifier structure: generic://sha256:/name + if packageType == "generic" { + lastSlashIndex := strings.LastIndex(packageId, "/") + return packageId[lastSlashIndex+1:], "", packageTypes[packageType] + } + + var compName, compVersion string + switch packageType { + case "rpm": + // RPM identifier structure: rpm://os-version:package:epoch-version:version + // os-version is optional. + splitCompId := strings.Split(packageId, ":") + if len(splitCompId) >= 3 { + compName = splitCompId[len(splitCompId)-3] + compVersion = fmt.Sprintf("%s:%s", splitCompId[len(splitCompId)-2], splitCompId[len(splitCompId)-1]) + } + default: + // All other identifiers look like this: package-type://package-name:version. + // Sometimes there's a namespace or a group before the package name, separated by a '/' or a ':'. + lastColonIndex := strings.LastIndex(packageId, ":") + + if lastColonIndex != -1 { + compName = packageId[:lastColonIndex] + compVersion = packageId[lastColonIndex+1:] + } + } + + // If there's an error while parsing the component ID + if compName == "" { + compName = packageId + } + + return compName, compVersion, packageTypes[packageType] +} \ No newline at end of file From e1f0fbb921fb08d7de7fa8ea5c8ad542e9df33b1 Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 30 Jun 2024 15:08:41 +0300 Subject: [PATCH 02/82] some fixes --- audit_test.go | 2 +- commands/scan/scan.go | 2 +- scans_test.go | 2 +- tests/utils/test_validation.go | 2 +- utils/formats/simplejsonapi.go | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/audit_test.go b/audit_test.go index 74b7da02..56317f96 100644 --- a/audit_test.go +++ b/audit_test.go @@ -13,7 +13,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-security/cli" "github.com/jfrog/jfrog-cli-security/cli/docs" - "github.com/jfrog/jfrog-cli-security/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils" xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" xscservices "github.com/jfrog/jfrog-client-go/xsc/services" diff --git a/commands/scan/scan.go b/commands/scan/scan.go index 6a4d12f7..b3d2e4f2 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -27,7 +27,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/common/spec" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-security/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils" xrutils "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-client-go/artifactory/services/fspatterns" diff --git a/scans_test.go b/scans_test.go index 13bd27c4..40141258 100644 --- a/scans_test.go +++ b/scans_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" biutils "github.com/jfrog/build-info-go/utils" - "github.com/jfrog/jfrog-cli-security/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/tests/utils/test_validation.go b/tests/utils/test_validation.go index 5b8514d1..2f407014 100644 --- a/tests/utils/test_validation.go +++ b/tests/utils/test_validation.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/jfrog/jfrog-cli-security/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils" clientUtils "github.com/jfrog/jfrog-client-go/utils" diff --git a/utils/formats/simplejsonapi.go b/utils/formats/simplejsonapi.go index 26ec121b..3166967c 100644 --- a/utils/formats/simplejsonapi.go +++ b/utils/formats/simplejsonapi.go @@ -84,6 +84,7 @@ type Location struct { type ComponentRow struct { Name string `json:"name"` Version string `json:"version"` + Location *Location `json:"location,omitempty"` } type CveRow struct { From 03946e97c631a8f12523107d3bc999d1f39add6b Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 30 Jun 2024 15:24:04 +0300 Subject: [PATCH 03/82] more refactor --- commands/scan/scan.go | 2 +- jas/applicability/applicabilitymanager.go | 2 +- jas/common.go | 2 +- jas/common_test.go | 2 +- jas/iac/iacscanner.go | 2 +- jas/sast/sastscanner.go | 2 +- jas/sast/sastscanner_test.go | 2 +- jas/secrets/secretsscanner.go | 2 +- scans_test.go | 7 +- .../formats}/sarifutils/sarifutils.go | 0 .../formats}/sarifutils/sarifutils_test.go | 0 .../formats}/sarifutils/test_sarifutils.go | 0 utils/formats/simplejsonapi.go | 4 +- utils/results.go | 4 +- utils/results/common.go | 18 +- utils/results/common_test.go | 873 ++++++++++++++++++ utils/results_test.go | 4 +- utils/resultstable.go | 16 +- utils/resultstable_test.go | 7 +- utils/resultwriter.go | 4 +- utils/resultwriter_test.go | 4 +- utils/securityJobSummary.go | 4 +- utils/securityJobSummary_test.go | 2 +- utils/severityutils/severity.go | 6 +- utils/techutils/techutils.go | 2 +- utils/xsc/analyticsmetrics_test.go | 2 +- xsc_test.go | 2 +- 27 files changed, 922 insertions(+), 53 deletions(-) rename {formats => utils/formats}/sarifutils/sarifutils.go (100%) rename {formats => utils/formats}/sarifutils/sarifutils_test.go (100%) rename {formats => utils/formats}/sarifutils/test_sarifutils.go (100%) create mode 100644 utils/results/common_test.go diff --git a/commands/scan/scan.go b/commands/scan/scan.go index d9f75b31..ce52854f 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -29,8 +29,8 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/common/spec" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-client-go/artifactory/services/fspatterns" clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/errorutils" diff --git a/jas/applicability/applicabilitymanager.go b/jas/applicability/applicabilitymanager.go index 3d426dcf..3913eece 100644 --- a/jas/applicability/applicabilitymanager.go +++ b/jas/applicability/applicabilitymanager.go @@ -5,9 +5,9 @@ import ( "github.com/jfrog/gofrog/datastructures" jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/jas" "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/log" diff --git a/jas/common.go b/jas/common.go index f58d4bf7..65ddd1df 100644 --- a/jas/common.go +++ b/jas/common.go @@ -16,8 +16,8 @@ import ( jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-cli-security/utils/severityutils" "github.com/jfrog/jfrog-cli-security/utils/techutils" diff --git a/jas/common_test.go b/jas/common_test.go index 09e90ac1..2a4ff8c1 100644 --- a/jas/common_test.go +++ b/jas/common_test.go @@ -4,8 +4,8 @@ import ( "os" "testing" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/owenrumney/go-sarif/v2/sarif" diff --git a/jas/iac/iacscanner.go b/jas/iac/iacscanner.go index e2f7094c..cb399033 100644 --- a/jas/iac/iacscanner.go +++ b/jas/iac/iacscanner.go @@ -4,8 +4,8 @@ import ( "path/filepath" jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/jas" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" clientutils "github.com/jfrog/jfrog-client-go/utils" diff --git a/jas/sast/sastscanner.go b/jas/sast/sastscanner.go index 5751c972..d4490609 100644 --- a/jas/sast/sastscanner.go +++ b/jas/sast/sastscanner.go @@ -5,8 +5,8 @@ import ( "path/filepath" jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/jas" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/log" diff --git a/jas/sast/sastscanner_test.go b/jas/sast/sastscanner_test.go index a6e21a5c..d136b0b7 100644 --- a/jas/sast/sastscanner_test.go +++ b/jas/sast/sastscanner_test.go @@ -4,8 +4,8 @@ import ( "path/filepath" "testing" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/jas" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/owenrumney/go-sarif/v2/sarif" "github.com/stretchr/testify/assert" diff --git a/jas/secrets/secretsscanner.go b/jas/secrets/secretsscanner.go index 89c82d06..039ddc8c 100644 --- a/jas/secrets/secretsscanner.go +++ b/jas/secrets/secretsscanner.go @@ -7,8 +7,8 @@ import ( clientutils "github.com/jfrog/jfrog-client-go/utils" jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/jas" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-client-go/utils/log" "github.com/owenrumney/go-sarif/v2/sarif" diff --git a/scans_test.go b/scans_test.go index 55965696..0e1f6088 100644 --- a/scans_test.go +++ b/scans_test.go @@ -3,9 +3,6 @@ package main import ( "encoding/json" "fmt" - biutils "github.com/jfrog/build-info-go/utils" - "github.com/jfrog/jfrog-cli-security/utils/formats" - "github.com/jfrog/jfrog-cli-security/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "net/http" @@ -18,10 +15,8 @@ import ( "testing" biutils "github.com/jfrog/build-info-go/utils" - "github.com/jfrog/jfrog-cli-security/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/jasutils" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/jfrog/jfrog-cli-security/cli" "github.com/jfrog/jfrog-cli-security/cli/docs" diff --git a/formats/sarifutils/sarifutils.go b/utils/formats/sarifutils/sarifutils.go similarity index 100% rename from formats/sarifutils/sarifutils.go rename to utils/formats/sarifutils/sarifutils.go diff --git a/formats/sarifutils/sarifutils_test.go b/utils/formats/sarifutils/sarifutils_test.go similarity index 100% rename from formats/sarifutils/sarifutils_test.go rename to utils/formats/sarifutils/sarifutils_test.go diff --git a/formats/sarifutils/test_sarifutils.go b/utils/formats/sarifutils/test_sarifutils.go similarity index 100% rename from formats/sarifutils/test_sarifutils.go rename to utils/formats/sarifutils/test_sarifutils.go diff --git a/utils/formats/simplejsonapi.go b/utils/formats/simplejsonapi.go index 3166967c..2365f075 100644 --- a/utils/formats/simplejsonapi.go +++ b/utils/formats/simplejsonapi.go @@ -82,8 +82,8 @@ type Location struct { } type ComponentRow struct { - Name string `json:"name"` - Version string `json:"version"` + Name string `json:"name"` + Version string `json:"version"` Location *Location `json:"location,omitempty"` } diff --git a/utils/results.go b/utils/results.go index dd51c053..3589b617 100644 --- a/utils/results.go +++ b/utils/results.go @@ -2,8 +2,8 @@ package utils import ( "github.com/jfrog/gofrog/datastructures" - "github.com/jfrog/jfrog-cli-security/formats" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-client-go/xray/services" "github.com/owenrumney/go-sarif/v2/sarif" diff --git a/utils/results/common.go b/utils/results/common.go index 0dbb4ac8..7c02504f 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" @@ -411,16 +412,17 @@ func getImpactPathKey(path []services.ImpactPathNode) string { return key } -func SplitScaScanResults(results *ScanCommandResults) ([]services.Violation, []services.Vulnerability, []services.License) { +func SplitScaScanResults(results *utils.ScaScanResult) ([]services.Violation, []services.Vulnerability, []services.License) { var violations []services.Violation var vulnerabilities []services.Vulnerability var licenses []services.License - for _, scan := range results.Scans { - for _, scaScan := range scan.ScaResults { - violations = append(violations, scaScan.XrayResult.Violations...) - vulnerabilities = append(vulnerabilities, scaScan.XrayResult.Vulnerabilities...) - licenses = append(licenses, scaScan.XrayResult.Licenses...) - } + for _, scan := range results.XrayResults { + licenses = append(licenses, scan.Licenses...) + // for _, scaScan := range scan.ScaResults { + // violations = append(violations, scaScan.XrayResult.Violations...) + // vulnerabilities = append(vulnerabilities, scaScan.XrayResult.Vulnerabilities...) + // licenses = append(licenses, scaScan.XrayResult.Licenses...) + // } } return violations, vulnerabilities, licenses } @@ -601,4 +603,4 @@ func getFinalApplicabilityStatus(applicabilityStatuses []jasutils.ApplicabilityS return jasutils.NotCovered } return jasutils.NotApplicable -} \ No newline at end of file +} diff --git a/utils/results/common_test.go b/utils/results/common_test.go new file mode 100644 index 00000000..c567aa9d --- /dev/null +++ b/utils/results/common_test.go @@ -0,0 +1,873 @@ +package results + +import ( + "path/filepath" + "testing" + + "github.com/owenrumney/go-sarif/v2/sarif" + "github.com/stretchr/testify/assert" + + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/severityutils" + "github.com/jfrog/jfrog-client-go/xray/services" +) + +func TestViolationFailBuild(t *testing.T) { + components := map[string]services.Component{"gav://antparent:ant:1.6.5": {}} + tests := []struct { + violations []services.Violation + expectedError bool + }{ + {[]services.Violation{{Components: components, FailBuild: false}, {Components: components, FailBuild: false}, {Components: components, FailBuild: false}}, false}, + {[]services.Violation{{Components: components, FailBuild: false}, {Components: components, FailBuild: true}, {Components: components, FailBuild: false}}, true}, + {[]services.Violation{{Components: components, FailBuild: true}, {Components: components, FailBuild: true}, {Components: components, FailBuild: true}}, true}, + } + + for _, test := range tests { + var err error + if CheckIfFailBuild([]services.ScanResponse{{Violations: test.violations}}) { + err = NewFailBuildError() + } + assert.Equal(t, test.expectedError, err != nil) + } +} + +func TestFindMaxCVEScore(t *testing.T) { + testCases := []struct { + name string + severity severityutils.Severity + status jasutils.ApplicabilityStatus + cves []formats.CveRow + expectedOutput string + expectedError bool + }{ + { + name: "CVEScore with valid float values", + severity: severityutils.High, + status: jasutils.Applicable, + cves: []formats.CveRow{{Id: "CVE-2021-1234", CvssV3: "7.5"}, {Id: "CVE-2021-5678", CvssV3: "9.2"}}, + expectedOutput: "9.2", + }, + { + name: "CVEScore with invalid float value", + severity: severityutils.High, + status: jasutils.Applicable, + cves: []formats.CveRow{{Id: "CVE-2022-4321", CvssV3: "invalid"}}, + expectedOutput: "", + expectedError: true, + }, + { + name: "CVEScore without values", + severity: severityutils.High, + status: jasutils.Applicable, + cves: []formats.CveRow{}, + expectedOutput: "8.9", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + output, err := FindMaxCVEScore(tc.severity, tc.status, tc.cves) + assert.False(t, tc.expectedError && err == nil) + assert.Equal(t, tc.expectedOutput, output) + }) + } +} + +func TestGetIssueIdentifier(t *testing.T) { + // issueId := "XRAY-123456" + // cvesRow := []formats.CveRow{{Id: "CVE-2022-1234"}} + // assert.Equal(t, "CVE-2022-1234", GetIssueIdentifier(cvesRow, issueId)) + // cvesRow = append(cvesRow, formats.CveRow{Id: "CVE-2019-1234"}) + // assert.Equal(t, "CVE-2022-1234, CVE-2019-1234", GetIssueIdentifier(cvesRow, issueId)) + // assert.Equal(t, issueId, GetIssueIdentifier(nil, issueId)) + + testCases := []struct { + name string + cves []formats.CveRow + delimiter string + issueId string + expectedOutput string + }{ + { + name: "Single CVE", + cves: []formats.CveRow{{Id: "CVE-2022-1234"}}, + delimiter: ",", + issueId: "XRAY-123456", + expectedOutput: "CVE-2022-1234", + }, + { + name: "Multiple CVEs", + cves: []formats.CveRow{{Id: "CVE-2022-1234"}, {Id: "CVE-2019-1234"}}, + delimiter: ",", + issueId: "XRAY-123456", + expectedOutput: "CVE-2022-1234, CVE-2019-1234", + }, + { + name: "No CVEs", + cves: nil, + delimiter: ",", + issueId: "XRAY-123456", + expectedOutput: "XRAY-123456", + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + output := GetIssueIdentifier(tc.cves, tc.issueId, tc.delimiter) + assert.Equal(t, tc.expectedOutput, output) + }) + } +} + +func TestIsImpactPathIsSubset(t *testing.T) { + testCases := []struct { + name string + target, source, expectedResult []services.ImpactPathNode + }{ + {"subset found in both target and source", + []services.ImpactPathNode{{ComponentId: "B"}, {ComponentId: "C"}}, + []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "C"}}, + []services.ImpactPathNode{{ComponentId: "B"}, {ComponentId: "C"}}, + }, + {"subset not found in both target and source", + []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "D"}}, + []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "C"}}, + []services.ImpactPathNode{}, + }, + {"target and source are identical", + []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}}, + []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}}, + []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := isImpactPathIsSubset(tc.target, tc.source) + assert.Equal(t, tc.expectedResult, result) + }) + } +} + +func TestAppendUniqueImpactPathsForMultipleRoots(t *testing.T) { + testCases := []struct { + name string + target [][]services.ImpactPathNode + source [][]services.ImpactPathNode + expectedResult [][]services.ImpactPathNode + }{ + { + name: "subset is found in both target and source", + target: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "C"}}, + {{ComponentId: "D"}, {ComponentId: "E"}}, + }, + source: [][]services.ImpactPathNode{ + {{ComponentId: "B"}, {ComponentId: "C"}}, + {{ComponentId: "F"}, {ComponentId: "G"}}, + }, + expectedResult: [][]services.ImpactPathNode{ + {{ComponentId: "B"}, {ComponentId: "C"}}, + {{ComponentId: "D"}, {ComponentId: "E"}}, + {{ComponentId: "F"}, {ComponentId: "G"}}, + }, + }, + { + name: "subset is not found in both target and source", + target: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "C"}}, + {{ComponentId: "D"}, {ComponentId: "E"}}, + }, + source: [][]services.ImpactPathNode{ + {{ComponentId: "B"}, {ComponentId: "C"}}, + {{ComponentId: "F"}, {ComponentId: "G"}}, + }, + expectedResult: [][]services.ImpactPathNode{ + {{ComponentId: "B"}, {ComponentId: "C"}}, + {{ComponentId: "D"}, {ComponentId: "E"}}, + {{ComponentId: "F"}, {ComponentId: "G"}}, + }, + }, + { + name: "target slice is empty", + target: [][]services.ImpactPathNode{}, + source: [][]services.ImpactPathNode{ + {{ComponentId: "E"}}, + {{ComponentId: "F"}, {ComponentId: "G"}}, + }, + expectedResult: [][]services.ImpactPathNode{ + {{ComponentId: "E"}}, + {{ComponentId: "F"}, {ComponentId: "G"}}, + }, + }, + { + name: "source slice is empty", + target: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}}, + {{ComponentId: "C"}, {ComponentId: "D"}}, + }, + source: [][]services.ImpactPathNode{}, + expectedResult: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}}, + {{ComponentId: "C"}, {ComponentId: "D"}}, + }, + }, + { + name: "target and source slices are identical", + target: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}}, + {{ComponentId: "C"}, {ComponentId: "D"}}, + }, + source: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}}, + {{ComponentId: "C"}, {ComponentId: "D"}}, + }, + expectedResult: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}}, + {{ComponentId: "C"}, {ComponentId: "D"}}, + }, + }, + { + name: "target and source slices contain multiple subsets", + target: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}}, + {{ComponentId: "C"}, {ComponentId: "D"}}, + }, + source: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "E"}}, + {{ComponentId: "C"}, {ComponentId: "D"}, {ComponentId: "F"}}, + {{ComponentId: "G"}, {ComponentId: "H"}}, + }, + expectedResult: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}}, + {{ComponentId: "C"}, {ComponentId: "D"}}, + {{ComponentId: "G"}, {ComponentId: "H"}}, + }, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + assert.Equal(t, test.expectedResult, AppendUniqueImpactPathsForMultipleRoots(test.target, test.source)) + }) + } +} + +func TestGetImpactPathKey(t *testing.T) { + testCases := []struct { + path []services.ImpactPathNode + expectedKey string + }{ + { + path: []services.ImpactPathNode{ + {ComponentId: "A"}, + {ComponentId: "B"}, + }, + expectedKey: "B", + }, + { + path: []services.ImpactPathNode{ + {ComponentId: "A"}, + }, + expectedKey: "A", + }, + } + + for _, test := range testCases { + key := getImpactPathKey(test.path) + assert.Equal(t, test.expectedKey, key) + } +} + +func TestAppendUniqueImpactPaths(t *testing.T) { + testCases := []struct { + name string + multipleRoots bool + target [][]services.ImpactPathNode + source [][]services.ImpactPathNode + expected [][]services.ImpactPathNode + }{ + { + name: "Test case 1: Unique impact paths found", + multipleRoots: false, + target: [][]services.ImpactPathNode{ + {{ComponentId: "A"}}, + {{ComponentId: "B"}}, + }, + source: [][]services.ImpactPathNode{ + {{ComponentId: "C"}}, + {{ComponentId: "D"}}, + }, + expected: [][]services.ImpactPathNode{ + {{ComponentId: "A"}}, + {{ComponentId: "B"}}, + {{ComponentId: "C"}}, + {{ComponentId: "D"}}, + }, + }, + { + name: "Test case 2: No unique impact paths found", + multipleRoots: false, + target: [][]services.ImpactPathNode{ + {{ComponentId: "A"}}, + {{ComponentId: "B"}}, + }, + source: [][]services.ImpactPathNode{ + {{ComponentId: "A"}}, + {{ComponentId: "B"}}, + }, + expected: [][]services.ImpactPathNode{ + {{ComponentId: "A"}}, + {{ComponentId: "B"}}, + }, + }, + { + name: "Test case 3: paths in source are not in target", + multipleRoots: false, + target: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}}, + {{ComponentId: "C"}, {ComponentId: "D"}}, + }, + source: [][]services.ImpactPathNode{ + {{ComponentId: "E"}}, + {{ComponentId: "F"}, {ComponentId: "G"}}, + }, + expected: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}}, + {{ComponentId: "C"}, {ComponentId: "D"}}, + {{ComponentId: "E"}}, + {{ComponentId: "F"}, {ComponentId: "G"}}, + }, + }, + { + name: "Test case 4: paths in source are already in target", + multipleRoots: false, + target: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}}, + {{ComponentId: "C"}, {ComponentId: "D"}}, + }, + source: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}}, + {{ComponentId: "C"}, {ComponentId: "D"}}, + }, + expected: [][]services.ImpactPathNode{ + {{ComponentId: "A"}, {ComponentId: "B"}}, + {{ComponentId: "C"}, {ComponentId: "D"}}, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := AppendUniqueImpactPaths(tc.target, tc.source, tc.multipleRoots) + assert.Equal(t, tc.expected, result) + }) + } +} + +// func TestGetXrayIssueLocationIfValidExists(t *testing.T) { +// testDir, cleanup := tests.CreateTempDirWithCallbackAndAssert(t) +// defer cleanup() +// invocation := sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(testDir)) +// file, err := os.Create(filepath.Join(testDir, "go.mod")) +// assert.NoError(t, err) +// assert.NotNil(t, file) +// defer func() { assert.NoError(t, file.Close()) }() +// file2, err := os.Create(filepath.Join(testDir, "build.gradle.kts")) +// assert.NoError(t, err) +// assert.NotNil(t, file2) +// defer func() { assert.NoError(t, file2.Close()) }() + +// testCases := []struct { +// name string +// tech techutils.Technology +// run *sarif.Run +// expectedOutput *sarif.Location +// }{ +// { +// name: "No descriptor information", +// tech: techutils.Pip, +// run: sarifutils.CreateRunWithDummyResults().WithInvocations([]*sarif.Invocation{invocation}), +// expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://Package-Descriptor"))), +// }, +// { +// name: "One descriptor information", +// tech: techutils.Go, +// run: sarifutils.CreateRunWithDummyResults().WithInvocations([]*sarif.Invocation{invocation}), +// expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://" + filepath.Join(testDir, "go.mod")))), +// }, +// { +// name: "One descriptor information - no invocation", +// tech: techutils.Go, +// run: sarifutils.CreateRunWithDummyResults(), +// expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://go.mod"))), +// }, +// { +// name: "Multiple descriptor information", +// tech: techutils.Gradle, +// run: sarifutils.CreateRunWithDummyResults().WithInvocations([]*sarif.Invocation{invocation}), +// expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://" + filepath.Join(testDir, "build.gradle.kts")))), +// }, +// } +// for _, tc := range testCases { +// t.Run(tc.name, func(t *testing.T) { +// output, err := getXrayIssueLocationIfValidExists(tc.tech, tc.run) +// if assert.NoError(t, err) { +// assert.Equal(t, tc.expectedOutput, output) +// } +// }) +// } +// } + +func TestGetApplicableCveValue(t *testing.T) { + // testCases := []struct { + // name string + // scanResults *ExtendedScanResults + // cves []services.Cve + // expectedResult jasutils.ApplicabilityStatus + // expectedCves []formats.CveRow + // }{ + // { + // name: "not entitled for jas", + // scanResults: &ExtendedScanResults{EntitledForJas: false}, + // expectedResult: jasutils.NotScanned, + // }, + // { + // name: "no cves", + // scanResults: &ExtendedScanResults{ + // ApplicabilityScanResults: []*sarif.Run{ + // sarifutils.CreateRunWithDummyResults( + // sarifutils.CreateResultWithOneLocation("fileName1", 0, 1, 0, 0, "snippet1", "applic_testCve1", "info"), + // sarifutils.CreateDummyPassingResult("applic_testCve2"), + // ), + // }, + // EntitledForJas: true, + // }, + // cves: nil, + // expectedResult: jasutils.NotCovered, + // expectedCves: nil, + // }, + // { + // name: "applicable cve", + // scanResults: &ExtendedScanResults{ + // ApplicabilityScanResults: []*sarif.Run{ + // sarifutils.CreateRunWithDummyResults( + // sarifutils.CreateDummyPassingResult("applic_testCve1"), + // sarifutils.CreateResultWithOneLocation("fileName2", 1, 0, 0, 0, "snippet2", "applic_testCve2", "warning"), + // ), + // }, + // EntitledForJas: true, + // }, + // cves: []services.Cve{{Id: "testCve2"}}, + // expectedResult: jasutils.Applicable, + // expectedCves: []formats.CveRow{{Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.Applicable)}}}, + // }, + // { + // name: "undetermined cve", + // scanResults: &ExtendedScanResults{ + // ApplicabilityScanResults: []*sarif.Run{ + // sarifutils.CreateRunWithDummyResults( + // sarifutils.CreateDummyPassingResult("applic_testCve1"), + // sarifutils.CreateResultWithOneLocation("fileName3", 0, 1, 0, 0, "snippet3", "applic_testCve2", "info"), + // ), + // }, + // EntitledForJas: true, + // }, + // cves: []services.Cve{{Id: "testCve3"}}, + // expectedResult: jasutils.ApplicabilityUndetermined, + // expectedCves: []formats.CveRow{{Id: "testCve3"}}, + // }, + // { + // name: "not applicable cve", + // scanResults: &ExtendedScanResults{ + // ApplicabilityScanResults: []*sarif.Run{ + // sarifutils.CreateRunWithDummyResults( + // sarifutils.CreateDummyPassingResult("applic_testCve1"), + // sarifutils.CreateDummyPassingResult("applic_testCve2"), + // ), + // }, + // EntitledForJas: true, + // }, + // cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, + // expectedResult: jasutils.NotApplicable, + // expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}}, + // }, + // { + // name: "applicable and not applicable cves", + // scanResults: &ExtendedScanResults{ + // ApplicabilityScanResults: []*sarif.Run{ + // sarifutils.CreateRunWithDummyResults( + // sarifutils.CreateDummyPassingResult("applic_testCve1"), + // sarifutils.CreateResultWithOneLocation("fileName4", 1, 0, 0, 0, "snippet", "applic_testCve2", "warning"), + // ), + // }, + // EntitledForJas: true, + // }, + // cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, + // expectedResult: jasutils.Applicable, + // expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.Applicable)}}}, + // }, + // { + // name: "undetermined and not applicable cves", + // scanResults: &ExtendedScanResults{ + // ApplicabilityScanResults: []*sarif.Run{ + // sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyPassingResult("applic_testCve1")), + // }, + // EntitledForJas: true}, + // cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, + // expectedResult: jasutils.ApplicabilityUndetermined, + // expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, {Id: "testCve2"}}, + // }, + // { + // name: "new scan statuses - applicable wins all statuses", + // scanResults: &ExtendedScanResults{ + // ApplicabilityScanResults: []*sarif.Run{ + // sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", sarifutils.CreateDummyPassingResult("applic_testCve1")), + // sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_testCve2")), + // sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve3")), + // }, + // EntitledForJas: true}, + // cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}, {Id: "testCve3"}}, + // expectedResult: jasutils.Applicable, + // expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.Applicable)}}, + // {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, + // {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.NotCovered)}}, + // }, + // }, + // { + // name: "new scan statuses - not covered wins not applicable", + // scanResults: &ExtendedScanResults{ + // ApplicabilityScanResults: []*sarif.Run{ + // sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve1")), + // sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_testCve2")), + // }, + // EntitledForJas: true}, + // cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, + // expectedResult: jasutils.NotCovered, + // expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotCovered)}}, + // {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, + // }, + // }, + // { + // name: "new scan statuses - undetermined wins not covered", + // scanResults: &ExtendedScanResults{ + // ApplicabilityScanResults: []*sarif.Run{ + // sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve1")), + // sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "undetermined", sarifutils.CreateDummyPassingResult("applic_testCve2")), + // }, + // EntitledForJas: true}, + // cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, + // expectedResult: jasutils.ApplicabilityUndetermined, + // expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotCovered)}}, + // {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.ApplicabilityUndetermined)}}, + // }, + // }, + // } + + testCases := []struct { + name string + entitledForJas bool + applicabilityScanResults []*sarif.Run + cves []services.Cve + components map[string]services.Component + expectedResult jasutils.ApplicabilityStatus + expectedCves []formats.CveRow + }{ + { + name: "not entitled for jas", + entitledForJas: false, + expectedResult: jasutils.NotScanned, + }, + { + name: "no cves", + entitledForJas: true, + applicabilityScanResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResults( + sarifutils.CreateResultWithOneLocation("fileName1", 0, 1, 0, 0, "snippet1", "applic_testCve1", "info"), + sarifutils.CreateDummyPassingResult("applic_testCve2"), + ), + }, + cves: nil, + expectedResult: jasutils.NotCovered, + expectedCves: nil, + }, + { + name: "applicable cve", + entitledForJas: true, + applicabilityScanResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResults( + sarifutils.CreateDummyPassingResult("applic_testCve1"), + sarifutils.CreateResultWithOneLocation("fileName2", 1, 0, 0, 0, "snippet2", "applic_testCve2", "warning"), + ), + }, + cves: []services.Cve{{Id: "testCve2"}}, + expectedResult: jasutils.Applicable, + expectedCves: []formats.CveRow{{Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.Applicable)}}}, + }, + { + name: "undetermined cve", + entitledForJas: true, + applicabilityScanResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResults( + sarifutils.CreateDummyPassingResult("applic_testCve1"), + sarifutils.CreateResultWithOneLocation("fileName3", 0, 1, 0, 0, "snippet3", "applic_testCve2", "info"), + ), + }, + cves: []services.Cve{{Id: "testCve3"}}, + expectedResult: jasutils.ApplicabilityUndetermined, + expectedCves: []formats.CveRow{{Id: "testCve3"}}, + }, + { + name: "not applicable cve", + entitledForJas: true, + applicabilityScanResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResults( + sarifutils.CreateDummyPassingResult("applic_testCve1"), + sarifutils.CreateDummyPassingResult("applic_testCve2"), + ), + }, + cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, + expectedResult: jasutils.NotApplicable, + expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}}, + }, + { + name: "applicable and not applicable cves", + entitledForJas: true, + applicabilityScanResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResults( + sarifutils.CreateDummyPassingResult("applic_testCve1"), + sarifutils.CreateResultWithOneLocation("fileName4", 1, 0, 0, 0, "snippet", "applic_testCve2", "warning"), + ), + }, + cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, + expectedResult: jasutils.Applicable, + expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.Applicable)}}}, + }, + { + name: "undetermined and not applicable cves", + entitledForJas: true, + applicabilityScanResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyPassingResult("applic_testCve1")), + }, + cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, + expectedResult: jasutils.ApplicabilityUndetermined, + expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, {Id: "testCve2"}}, + }, + { + name: "new scan statuses - applicable wins all statuses", + entitledForJas: true, + applicabilityScanResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", sarifutils.CreateDummyPassingResult("applic_testCve1")), + sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_testCve2")), + sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve3")), + }, + cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}, {Id: "testCve3"}}, + expectedResult: jasutils.Applicable, + expectedCves: []formats.CveRow{ + {Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.Applicable)}}, + {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, + {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.NotCovered)}}, + }, + }, + { + name: "new scan statuses - not covered wins not applicable", + entitledForJas: true, + applicabilityScanResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve1")), + sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_testCve2")), + }, + cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, + expectedResult: jasutils.NotCovered, + expectedCves: []formats.CveRow{ + {Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotCovered)}}, + {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, + }, + }, + { + name: "new scan statuses - undetermined wins not covered", + entitledForJas: true, + applicabilityScanResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve1")), + sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "undetermined", sarifutils.CreateDummyPassingResult("applic_testCve2")), + }, + cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, + expectedResult: jasutils.ApplicabilityUndetermined, + expectedCves: []formats.CveRow{ + {Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotCovered)}}, + {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.ApplicabilityUndetermined)}}, + }, + }, + { + name: "disqualified evidence", + entitledForJas: true, + applicabilityScanResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResults( + sarifutils.CreateDummyPassingResult("applic_testCve1"), + sarifutils.CreateResultWithOneLocation("fileName4", 1, 0, 0, 0, "snippet", "applic_testCve2", "warning"), + ), + }, + cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, + components: map[string]services.Component{ + "npm://protobufjs:6.11.2": services.Component{ImpactPaths: [][]services.ImpactPathNode{{services.ImpactPathNode{FullPath: "fileName4", ComponentId: "npm://mquery:3.2.2"}}}}, + "npm://mquery:3.2.2": {}, + }, + expectedResult: jasutils.Applicable, + expectedCves: []formats.CveRow{ + {Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, + {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.Applicable)}}, + }, + }, + } + + for _, testCase := range testCases { + cves := convertCves(testCase.cves) + for i := range cves { + cves[i].Applicability = GetCveApplicabilityField(cves[i].Id, testCase.applicabilityScanResults, testCase.components) + } + applicableValue := GetApplicableCveStatus(testCase.entitledForJas, testCase.applicabilityScanResults, cves) + assert.Equal(t, testCase.expectedResult, applicableValue) + if assert.True(t, len(testCase.expectedCves) == len(cves)) { + for i := range cves { + if testCase.expectedCves[i].Applicability != nil && assert.NotNil(t, cves[i].Applicability) { + assert.Equal(t, testCase.expectedCves[i].Applicability.Status, cves[i].Applicability.Status) + assert.ElementsMatch(t, testCase.expectedCves[i].Applicability.Evidence, cves[i].Applicability.Evidence) + } + } + } + } +} + +func TestShouldDisqualifyEvidence(t *testing.T) { + testCases := []struct { + name string + component map[string]services.Component + filePath string + disqualify bool + }{ + { + name: "package folders", + component: map[string]services.Component{"npm://protobufjs:6.11.2": {}}, + filePath: "file:///Users/jfrog/test/node_modules/protobufjs/src/badCode.js", + disqualify: true, + }, { + name: "nested folders", + component: map[string]services.Component{"npm://protobufjs:6.11.2": {}}, + filePath: "file:///Users/jfrog/test/node_modules/someDep/node_modules/protobufjs/src/badCode.js", + disqualify: true, + }, { + name: "applicability in node modules", + component: map[string]services.Component{"npm://protobufjs:6.11.2": {}}, + filePath: "file:///Users/jfrog/test/node_modules/mquery/src/badCode.js", + disqualify: false, + }, { + // Only npm supported + name: "not npm", + component: map[string]services.Component{"yarn://protobufjs:6.11.2": {}}, + filePath: "file:///Users/jfrog/test/node_modules/protobufjs/src/badCode.js", + disqualify: false, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.disqualify, shouldDisqualifyEvidence(tc.component, tc.filePath)) + }) + } +} + +func TestGetDirectComponents(t *testing.T) { + tests := []struct { + name string + target string + impactPaths [][]services.ImpactPathNode + expectedDirectComponentRows []formats.ComponentRow + expectedConvImpactPaths [][]formats.ComponentRow + }{ + { + name: "one direct component", + impactPaths: [][]services.ImpactPathNode{{services.ImpactPathNode{ComponentId: "gav://jfrog:pack:1.2.3"}}}, + expectedDirectComponentRows: []formats.ComponentRow{{Name: "jfrog:pack", Version: "1.2.3"}}, + expectedConvImpactPaths: [][]formats.ComponentRow{{{Name: "jfrog:pack", Version: "1.2.3"}}}, + }, + { + name: "one direct component with target", + target: filepath.Join("root", "dir", "file"), + impactPaths: [][]services.ImpactPathNode{{ + services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, + services.ImpactPathNode{ComponentId: "gav://jfrog:pack2:1.2.3"}, + }}, + expectedDirectComponentRows: []formats.ComponentRow{{Name: "jfrog:pack1", Version: "1.2.3", Location: &formats.Location{File: filepath.Join("root", "dir", "file")}}}, + expectedConvImpactPaths: [][]formats.ComponentRow{{{Name: "jfrog:pack1", Version: "1.2.3"}, {Name: "jfrog:pack2", Version: "1.2.3"}}}, + }, + { + name: "multiple direct components", + target: filepath.Join("root", "dir", "file"), + impactPaths: [][]services.ImpactPathNode{ + { + services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, + services.ImpactPathNode{ComponentId: "gav://jfrog:pack2:1.2.3"}, + services.ImpactPathNode{ComponentId: "gav://jfrog:pack3:1.2.3"}, + }, + { + services.ImpactPathNode{ComponentId: "gav://jfrog:pack4:1.2.3"}, + services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, + }, + }, + expectedDirectComponentRows: []formats.ComponentRow{ + {Name: "jfrog:pack1", Version: "1.2.3", Location: &formats.Location{File: filepath.Join("root", "dir", "file")}}, + {Name: "jfrog:pack4", Version: "1.2.3", Location: &formats.Location{File: filepath.Join("root", "dir", "file")}}, + }, + expectedConvImpactPaths: [][]formats.ComponentRow{ + {{Name: "jfrog:pack1", Version: "1.2.3"}, {Name: "jfrog:pack2", Version: "1.2.3"}, {Name: "jfrog:pack3", Version: "1.2.3"}}, + {{Name: "jfrog:pack4", Version: "1.2.3"}, {Name: "jfrog:pack1", Version: "1.2.3"}}, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actualComponentRows, actualConvImpactPaths := getDirectComponentsAndImpactPaths(test.target, test.impactPaths) + assert.ElementsMatch(t, test.expectedDirectComponentRows, actualComponentRows) + assert.ElementsMatch(t, test.expectedConvImpactPaths, actualConvImpactPaths) + }) + } +} + +func TestGetFinalApplicabilityStatus(t *testing.T) { + testCases := []struct { + name string + input []jasutils.ApplicabilityStatus + expectedOutput jasutils.ApplicabilityStatus + }{ + { + name: "applicable wins all statuses", + input: []jasutils.ApplicabilityStatus{jasutils.ApplicabilityUndetermined, jasutils.Applicable, jasutils.NotCovered, jasutils.NotApplicable}, + expectedOutput: jasutils.Applicable, + }, + { + name: "undetermined wins not covered", + input: []jasutils.ApplicabilityStatus{jasutils.NotCovered, jasutils.ApplicabilityUndetermined, jasutils.NotCovered, jasutils.NotApplicable}, + expectedOutput: jasutils.ApplicabilityUndetermined, + }, + { + name: "not covered wins not applicable", + input: []jasutils.ApplicabilityStatus{jasutils.NotApplicable, jasutils.NotCovered, jasutils.NotApplicable}, + expectedOutput: jasutils.NotCovered, + }, + { + name: "all statuses are not applicable", + input: []jasutils.ApplicabilityStatus{jasutils.NotApplicable, jasutils.NotApplicable, jasutils.NotApplicable}, + expectedOutput: jasutils.NotApplicable, + }, + { + name: "no statuses", + input: []jasutils.ApplicabilityStatus{}, + expectedOutput: jasutils.NotScanned, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.expectedOutput, getFinalApplicabilityStatus(tc.input)) + }) + } +} diff --git a/utils/results_test.go b/utils/results_test.go index 6ed05739..a5f87048 100644 --- a/utils/results_test.go +++ b/utils/results_test.go @@ -3,8 +3,8 @@ package utils import ( "testing" - "github.com/jfrog/jfrog-cli-security/formats" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-client-go/xray/services" "github.com/owenrumney/go-sarif/v2/sarif" "github.com/stretchr/testify/assert" diff --git a/utils/resultstable.go b/utils/resultstable.go index dccf1788..63b2666d 100644 --- a/utils/resultstable.go +++ b/utils/resultstable.go @@ -11,8 +11,8 @@ import ( "github.com/jfrog/gofrog/datastructures" "github.com/owenrumney/go-sarif/v2/sarif" - "github.com/jfrog/jfrog-cli-security/formats" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-cli-security/utils/severityutils" "github.com/jfrog/jfrog-cli-security/utils/techutils" @@ -528,7 +528,7 @@ func splitComponents(impactedPackages map[string]services.Component) (impactedPa return } for currCompId, currComp := range impactedPackages { - currCompName, currCompVersion, currCompType := SplitComponentId(currCompId) + currCompName, currCompVersion, currCompType := techutils.SplitComponentId(currCompId) impactedPackagesNames = append(impactedPackagesNames, currCompName) impactedPackagesVersions = append(impactedPackagesVersions, currCompVersion) impactedPackagesTypes = append(impactedPackagesTypes, currCompType) @@ -540,8 +540,6 @@ func splitComponents(impactedPackages map[string]services.Component) (impactedPa return } - - // Gets a slice of the direct dependencies or packages of the scanned component, that depends on the vulnerable package, and converts the impact paths. func getDirectComponentsAndImpactPaths(impactPaths [][]services.ImpactPathNode) (components []formats.ComponentRow, impactPathsRows [][]formats.ComponentRow) { componentsMap := make(map[string]formats.ComponentRow) @@ -555,14 +553,14 @@ func getDirectComponentsAndImpactPaths(impactPaths [][]services.ImpactPathNode) } componentId := impactPath[impactPathIndex].ComponentId if _, exist := componentsMap[componentId]; !exist { - compName, compVersion, _ := SplitComponentId(componentId) + compName, compVersion, _ := techutils.SplitComponentId(componentId) componentsMap[componentId] = formats.ComponentRow{Name: compName, Version: compVersion} } // Convert the impact path var compImpactPathRows []formats.ComponentRow for _, pathNode := range impactPath { - nodeCompName, nodeCompVersion, _ := SplitComponentId(pathNode.ComponentId) + nodeCompName, nodeCompVersion, _ := techutils.SplitComponentId(pathNode.ComponentId) compImpactPathRows = append(compImpactPathRows, formats.ComponentRow{ Name: nodeCompName, Version: nodeCompVersion, @@ -626,7 +624,7 @@ func simplifyVulnerabilities(scanVulnerabilities []services.Vulnerability, multi var uniqueVulnerabilities = make(map[string]*services.Vulnerability) for _, vulnerability := range scanVulnerabilities { for vulnerableComponentId := range vulnerability.Components { - vulnerableDependency, vulnerableVersion, _ := SplitComponentId(vulnerableComponentId) + vulnerableDependency, vulnerableVersion, _ := techutils.SplitComponentId(vulnerableComponentId) packageKey := GetUniqueKey(vulnerableDependency, vulnerableVersion, vulnerability.IssueId, len(vulnerability.Components[vulnerableComponentId].FixedVersions) > 0) if uniqueVulnerability, exist := uniqueVulnerabilities[packageKey]; exist { fixedVersions := appendUniqueFixVersions(uniqueVulnerability.Components[vulnerableComponentId].FixedVersions, vulnerability.Components[vulnerableComponentId].FixedVersions...) @@ -662,7 +660,7 @@ func simplifyViolations(scanViolations []services.Violation, multipleRoots bool) var uniqueViolations = make(map[string]*services.Violation) for _, violation := range scanViolations { for vulnerableComponentId := range violation.Components { - vulnerableDependency, vulnerableVersion, _ := SplitComponentId(vulnerableComponentId) + vulnerableDependency, vulnerableVersion, _ := techutils.SplitComponentId(vulnerableComponentId) packageKey := GetUniqueKey(vulnerableDependency, vulnerableVersion, violation.IssueId, len(violation.Components[vulnerableComponentId].FixedVersions) > 0) if uniqueVulnerability, exist := uniqueViolations[packageKey]; exist { fixedVersions := appendUniqueFixVersions(uniqueVulnerability.Components[vulnerableComponentId].FixedVersions, violation.Components[vulnerableComponentId].FixedVersions...) diff --git a/utils/resultstable_test.go b/utils/resultstable_test.go index 8f259290..87d8c7cc 100644 --- a/utils/resultstable_test.go +++ b/utils/resultstable_test.go @@ -4,9 +4,10 @@ import ( "fmt" "testing" - "github.com/jfrog/jfrog-cli-security/formats" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/owenrumney/go-sarif/v2/sarif" "github.com/jfrog/jfrog-client-go/xray/services" @@ -58,7 +59,7 @@ func TestSplitComponentId(t *testing.T) { } for _, test := range tests { - actualCompName, actualCompVersion, actualCompType := SplitComponentId(test.componentId) + actualCompName, actualCompVersion, actualCompType := techutils.SplitComponentId(test.componentId) assert.Equal(t, test.expectedCompName, actualCompName) assert.Equal(t, test.expectedCompVersion, actualCompVersion) assert.Equal(t, test.expectedCompType, actualCompType) diff --git a/utils/resultwriter.go b/utils/resultwriter.go index 306f1887..03aa0c9f 100644 --- a/utils/resultwriter.go +++ b/utils/resultwriter.go @@ -9,8 +9,8 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/common/format" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-security/formats" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-cli-security/utils/severityutils" "github.com/jfrog/jfrog-cli-security/utils/techutils" diff --git a/utils/resultwriter_test.go b/utils/resultwriter_test.go index 76997a29..417ed1fe 100644 --- a/utils/resultwriter_test.go +++ b/utils/resultwriter_test.go @@ -6,8 +6,8 @@ import ( "testing" "github.com/jfrog/jfrog-cli-core/v2/utils/tests" - "github.com/jfrog/jfrog-cli-security/formats" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-client-go/xray/services" diff --git a/utils/securityJobSummary.go b/utils/securityJobSummary.go index 136d1b1b..bfea6497 100644 --- a/utils/securityJobSummary.go +++ b/utils/securityJobSummary.go @@ -8,8 +8,8 @@ import ( "github.com/jfrog/gofrog/datastructures" "github.com/jfrog/jfrog-cli-core/v2/commandsummary" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-security/formats" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-cli-security/utils/severityutils" "github.com/jfrog/jfrog-client-go/utils/log" diff --git a/utils/securityJobSummary_test.go b/utils/securityJobSummary_test.go index c8bd562e..e04d3396 100644 --- a/utils/securityJobSummary_test.go +++ b/utils/securityJobSummary_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/jfrog/jfrog-cli-security/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/stretchr/testify/assert" ) diff --git a/utils/severityutils/severity.go b/utils/severityutils/severity.go index 3cc256f6..dab73675 100644 --- a/utils/severityutils/severity.go +++ b/utils/severityutils/severity.go @@ -6,7 +6,7 @@ import ( "github.com/gookit/color" "github.com/jfrog/gofrog/datastructures" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-security/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-client-go/utils/errorutils" "golang.org/x/text/cases" @@ -14,8 +14,8 @@ import ( ) const ( - MinCveScore = 0.0 - MaxCveScore = 10.0 + MinCveScore float32 = 0.0 + MaxCveScore float32 = 10.0 // When parsing Sarif level to severity, // If the level is not provided, the value is defaulted to be 'Medium' SeverityDefaultValue = Medium diff --git a/utils/techutils/techutils.go b/utils/techutils/techutils.go index 7c2d69be..0b89dd72 100644 --- a/utils/techutils/techutils.go +++ b/utils/techutils/techutils.go @@ -570,4 +570,4 @@ func SplitComponentId(componentId string) (string, string, string) { } return compName, compVersion, packageTypes[packageType] -} \ No newline at end of file +} diff --git a/utils/xsc/analyticsmetrics_test.go b/utils/xsc/analyticsmetrics_test.go index 9145b526..a839a9ce 100644 --- a/utils/xsc/analyticsmetrics_test.go +++ b/utils/xsc/analyticsmetrics_test.go @@ -7,8 +7,8 @@ import ( "time" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-client-go/utils/tests" "github.com/jfrog/jfrog-client-go/xray/services" xscservices "github.com/jfrog/jfrog-client-go/xsc/services" diff --git a/xsc_test.go b/xsc_test.go index 56ca5d3c..a929ad00 100644 --- a/xsc_test.go +++ b/xsc_test.go @@ -12,7 +12,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-security/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/xray/scangraph" "github.com/jfrog/jfrog-cli-security/utils/xsc" From fe6d86d902c36a1b7e73ae4dd127fa490fd6ea7d Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 30 Jun 2024 15:53:37 +0300 Subject: [PATCH 04/82] continue refactor --- commands/audit/audit.go | 23 +- commands/audit/scarunner.go | 15 +- commands/audit/scarunner_test.go | 8 +- commands/scan/buildscan.go | 5 +- commands/scan/dockerscan.go | 3 +- commands/scan/scan.go | 15 +- jas/runner/jasrunner.go | 11 +- jas/runner/jasrunner_test.go | 6 +- utils/results/common.go | 3 +- utils/results/conversion/convertor.go | 251 ++++++++++++++++++ .../conversion/sarifparser/sarifparser.go | 1 + .../simplejsonparser/simplejsonparser.go | 1 + .../conversion/summaryparser/summaryparser.go | 1 + .../conversion/tableparser/tableparser.go | 1 + utils/{ => results}/results.go | 26 +- utils/{ => results}/results_test.go | 24 +- utils/resultstable.go | 34 +-- utils/resultwriter.go | 81 +++--- utils/xsc/analyticsmetrics.go | 4 +- utils/xsc/analyticsmetrics_test.go | 15 +- 20 files changed, 396 insertions(+), 132 deletions(-) create mode 100644 utils/results/conversion/convertor.go create mode 100644 utils/results/conversion/sarifparser/sarifparser.go create mode 100644 utils/results/conversion/simplejsonparser/simplejsonparser.go create mode 100644 utils/results/conversion/summaryparser/summaryparser.go create mode 100644 utils/results/conversion/tableparser/tableparser.go rename utils/{ => results}/results.go (84%) rename utils/{ => results}/results_test.go (92%) diff --git a/commands/audit/audit.go b/commands/audit/audit.go index fa4acf9b..91d6a6a4 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -11,6 +11,7 @@ import ( "github.com/jfrog/jfrog-cli-security/jas/applicability" "github.com/jfrog/jfrog-cli-security/jas/runner" "github.com/jfrog/jfrog-cli-security/jas/secrets" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/xray/scangraph" "github.com/jfrog/jfrog-cli-security/utils/xsc" @@ -179,9 +180,9 @@ func (auditCmd *AuditCommand) CommandName() string { // Runs an audit scan based on the provided auditParams. // Returns an audit Results object containing all the scan results. // If the current server is entitled for JAS, the advanced security results will be included in the scan results. -func RunAudit(auditParams *AuditParams) (results *utils.Results, err error) { +func RunAudit(auditParams *AuditParams) (cmdResults *results.ScanCommandResults, err error) { // Initialize Results struct - results = utils.NewAuditResults() + cmdResults = results.NewAuditResults() serverDetails, err := auditParams.ServerDetails() if err != nil { return @@ -193,32 +194,32 @@ func RunAudit(auditParams *AuditParams) (results *utils.Results, err error) { if err = clientutils.ValidateMinimumVersion(clientutils.Xray, auditParams.xrayVersion, scangraph.GraphScanMinXrayVersion); err != nil { return } - results.XrayVersion = auditParams.xrayVersion - results.ExtendedScanResults.EntitledForJas, err = isEntitledForJas(xrayManager, auditParams) + cmdResults.XrayVersion = auditParams.xrayVersion + cmdResults.ExtendedScanResults.EntitledForJas, err = isEntitledForJas(xrayManager, auditParams) if err != nil { return } - results.MultiScanId = auditParams.commonGraphScanParams.MultiScanId + cmdResults.MultiScanId = auditParams.commonGraphScanParams.MultiScanId auditParallelRunner := utils.CreateSecurityParallelRunner(auditParams.threads) auditParallelRunner.ErrWg.Add(1) jfrogAppsConfig, err := jas.CreateJFrogAppsConfig(auditParams.workingDirs) if err != nil { - return results, fmt.Errorf("failed to create JFrogAppsConfig: %s", err.Error()) + return cmdResults, fmt.Errorf("failed to create JFrogAppsConfig: %s", err.Error()) } jasScanner := &jas.JasScanner{} - if results.ExtendedScanResults.EntitledForJas { + if cmdResults.ExtendedScanResults.EntitledForJas { // Download (if needed) the analyzer manager and run scanners. auditParallelRunner.JasWg.Add(1) if _, jasErr := auditParallelRunner.Runner.AddTaskWithError(func(threadId int) error { - return downloadAnalyzerManagerAndRunScanners(auditParallelRunner, results, serverDetails, auditParams, jasScanner, jfrogAppsConfig, threadId) + return downloadAnalyzerManagerAndRunScanners(auditParallelRunner, cmdResults, serverDetails, auditParams, jasScanner, jfrogAppsConfig, threadId) }, auditParallelRunner.AddErrorToChan); jasErr != nil { auditParallelRunner.AddErrorToChan(fmt.Errorf("failed to create AM downloading task, skipping JAS scans...: %s", jasErr.Error())) } } // The sca scan doesn't require the analyzer manager, so it can run separately from the analyzer manager download routine. - if scaScanErr := buildDepTreeAndRunScaScan(auditParallelRunner, auditParams, results); scaScanErr != nil { + if scaScanErr := buildDepTreeAndRunScaScan(auditParallelRunner, auditParams, cmdResults); scaScanErr != nil { auditParallelRunner.AddErrorToChan(scaScanErr) } go func() { @@ -237,7 +238,7 @@ func RunAudit(auditParams *AuditParams) (results *utils.Results, err error) { go func() { defer auditParallelRunner.ErrWg.Done() for e := range auditParallelRunner.ErrorsQueue { - results.ScansErr = errors.Join(results.ScansErr, e) + cmdResults.ScansErr = errors.Join(cmdResults.ScansErr, e) } }() if auditParams.Progress() != nil { @@ -256,7 +257,7 @@ func isEntitledForJas(xrayManager *xray.XrayServicesManager, auditParams *AuditP return jas.IsEntitledForJas(xrayManager, auditParams.xrayVersion) } -func downloadAnalyzerManagerAndRunScanners(auditParallelRunner *utils.SecurityParallelRunner, scanResults *utils.Results, +func downloadAnalyzerManagerAndRunScanners(auditParallelRunner *utils.SecurityParallelRunner, scanResults *results.ScanCommandResults, serverDetails *config.ServerDetails, auditParams *AuditParams, scanner *jas.JasScanner, jfrogAppsConfig *jfrogappsconfig.JFrogAppsConfig, threadId int) (err error) { defer func() { auditParallelRunner.JasWg.Done() diff --git a/commands/audit/scarunner.go b/commands/audit/scarunner.go index 0f2fcd2a..6ba78fda 100644 --- a/commands/audit/scarunner.go +++ b/commands/audit/scarunner.go @@ -27,6 +27,7 @@ import ( "github.com/jfrog/jfrog-cli-security/commands/audit/sca/yarn" "github.com/jfrog/jfrog-cli-security/utils" xrayutils "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-cli-security/utils/xray" "github.com/jfrog/jfrog-cli-security/utils/xray/scangraph" @@ -37,7 +38,7 @@ import ( xrayCmdUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" ) -func buildDepTreeAndRunScaScan(auditParallelRunner *utils.SecurityParallelRunner, auditParams *AuditParams, results *xrayutils.Results) (err error) { +func buildDepTreeAndRunScaScan(auditParallelRunner *utils.SecurityParallelRunner, auditParams *AuditParams, cmdResults *results.ScanCommandResults) (err error) { if len(auditParams.ScansToPerform()) > 0 && !slices.Contains(auditParams.ScansToPerform(), xrayutils.ScaScan) { log.Debug("Skipping SCA scan as requested by input...") return @@ -84,14 +85,14 @@ func buildDepTreeAndRunScaScan(auditParallelRunner *utils.SecurityParallelRunner } // Add the scan to the results auditParallelRunner.ResultsMu.Lock() - results.ScaResults = append(results.ScaResults, scan) + cmdResults.ScaResults = append(cmdResults.ScaResults, scan) auditParallelRunner.ResultsMu.Unlock() } return } // Calculate the scans to preform -func getScaScansToPreform(params *AuditParams) (scansToPreform []*xrayutils.ScaScanResult) { +func getScaScansToPreform(params *AuditParams) (scansToPreform []*results.ScaScanResult) { for _, requestedDirectory := range params.workingDirs { if !fileutils.IsPathExists(requestedDirectory, false) { log.Warn("The working directory", requestedDirectory, "doesn't exist. Skipping SCA scan...") @@ -112,11 +113,11 @@ func getScaScansToPreform(params *AuditParams) (scansToPreform []*xrayutils.ScaS } if len(workingDirs) == 0 { // Requested technology (from params) descriptors/indicators was not found, scan only requested directory for this technology. - scansToPreform = append(scansToPreform, &xrayutils.ScaScanResult{Target: requestedDirectory, Technology: tech}) + scansToPreform = append(scansToPreform, &results.ScaScanResult{Target: requestedDirectory, Technology: tech}) } for workingDir, descriptors := range workingDirs { // Add scan for each detected working directory. - scansToPreform = append(scansToPreform, &xrayutils.ScaScanResult{Target: workingDir, Technology: tech, Descriptors: descriptors}) + scansToPreform = append(scansToPreform, &results.ScaScanResult{Target: workingDir, Technology: tech, Descriptors: descriptors}) } } } @@ -133,7 +134,7 @@ func getRequestedDescriptors(params *AuditParams) map[techutils.Technology][]str // Preform the SCA scan for the given scan information. func executeScaScanTask(auditParallelRunner *utils.SecurityParallelRunner, serverDetails *config.ServerDetails, auditParams *AuditParams, - scan *xrayutils.ScaScanResult, treeResult *DependencyTreeResult) parallel.TaskFunc { + scan *results.ScaScanResult, treeResult *DependencyTreeResult) parallel.TaskFunc { return func(threadId int) (err error) { log.Info(clientutils.GetLogMsgPrefix(threadId, false)+"Running SCA scan for", scan.Target, "vulnerable dependencies in", scan.Target, "directory...") defer func() { @@ -411,7 +412,7 @@ func logDeps(uniqueDeps any) (err error) { } // This method will change the working directory to the scan's working directory. -func buildDependencyTree(scan *utils.ScaScanResult, params *AuditParams) (*DependencyTreeResult, error) { +func buildDependencyTree(scan *results.ScaScanResult, params *AuditParams) (*DependencyTreeResult, error) { if err := os.Chdir(scan.Target); err != nil { return nil, errorutils.CheckError(err) } diff --git a/commands/audit/scarunner_test.go b/commands/audit/scarunner_test.go index 1a265381..fb3f52af 100644 --- a/commands/audit/scarunner_test.go +++ b/commands/audit/scarunner_test.go @@ -6,7 +6,7 @@ import ( "sort" "testing" - xrayutils "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" @@ -125,7 +125,7 @@ func TestGetScaScansToPreform(t *testing.T) { name string wd string params func() *AuditParams - expected []*xrayutils.ScaScanResult + expected []*results.ScaScanResult }{ { name: "Test specific technologies", @@ -135,7 +135,7 @@ func TestGetScaScansToPreform(t *testing.T) { param.SetTechnologies([]string{"maven", "npm", "go"}).SetIsRecursiveScan(true) return param }, - expected: []*xrayutils.ScaScanResult{ + expected: []*results.ScaScanResult{ { Technology: techutils.Maven, Target: filepath.Join(dir, "dir", "maven"), @@ -165,7 +165,7 @@ func TestGetScaScansToPreform(t *testing.T) { param.SetIsRecursiveScan(true) return param }, - expected: []*xrayutils.ScaScanResult{ + expected: []*results.ScaScanResult{ { Technology: techutils.Maven, Target: filepath.Join(dir, "dir", "maven"), diff --git a/commands/scan/buildscan.go b/commands/scan/buildscan.go index b00375fd..f5d2009b 100644 --- a/commands/scan/buildscan.go +++ b/commands/scan/buildscan.go @@ -8,6 +8,7 @@ import ( outputFormat "github.com/jfrog/jfrog-cli-core/v2/common/format" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/results" xrayutils "github.com/jfrog/jfrog-cli-security/utils/xray" clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/log" @@ -129,9 +130,9 @@ func (bsc *BuildScanCommand) runBuildScanAndPrintResults(xrayManager *xray.XrayS XrayDataUrl: buildScanResults.MoreDetailsUrl, }} - scanResults := utils.NewAuditResults() + scanResults := results.NewAuditResults() scanResults.XrayVersion = xrayVersion - scanResults.ScaResults = []*utils.ScaScanResult{{Target: fmt.Sprintf("%s (%s)", params.BuildName, params.BuildNumber), XrayResults: scanResponse}} + scanResults.ScaResults = []*results.ScaScanResult{{Target: fmt.Sprintf("%s (%s)", params.BuildName, params.BuildNumber), XrayResults: scanResponse}} resultsPrinter := utils.NewResultsWriter(scanResults). SetOutputFormat(bsc.outputFormat). diff --git a/commands/scan/dockerscan.go b/commands/scan/dockerscan.go index 116f5a82..26f9a45d 100644 --- a/commands/scan/dockerscan.go +++ b/commands/scan/dockerscan.go @@ -10,6 +10,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/common/spec" "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/xray" clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/errorutils" @@ -94,7 +95,7 @@ func (dsc *DockerScanCommand) Run() (err error) { err = errorutils.CheckError(e) } }() - return dsc.ScanCommand.RunAndRecordResults(func(scanResults *utils.Results) (err error) { + return dsc.ScanCommand.RunAndRecordResults(func(scanResults *results.ScanCommandResults) (err error) { if scanResults == nil || len(scanResults.ScaResults) == 0 { return } diff --git a/commands/scan/scan.go b/commands/scan/scan.go index ce52854f..3e58329e 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -17,6 +17,7 @@ import ( "github.com/jfrog/jfrog-cli-security/jas/applicability" "github.com/jfrog/jfrog-cli-security/jas/runner" "github.com/jfrog/jfrog-cli-security/jas/secrets" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/severityutils" "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-cli-security/utils/xray" @@ -46,7 +47,7 @@ type indexFileHandlerFunc func(file string) type ScanInfo struct { Target string Result *services.ScanResponse - ExtendedScanResults *utils.ExtendedScanResults + ExtendedScanResults *results.ExtendedScanResults } const ( @@ -183,12 +184,12 @@ func (scanCmd *ScanCommand) indexFile(filePath string) (*xrayUtils.BinaryGraphNo } func (scanCmd *ScanCommand) Run() (err error) { - return scanCmd.RunAndRecordResults(func(scanResults *utils.Results) error { + return scanCmd.RunAndRecordResults(func(scanResults *results.ScanCommandResults) error { return utils.RecordSecurityCommandOutput(utils.ScanCommandSummaryResult{Results: scanResults.GetSummary(), Section: utils.Binary}) }) } -func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults *utils.Results) error) (err error) { +func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults *results.ScanCommandResults) error) (err error) { defer func() { if err != nil { var e *exec.ExitError @@ -204,7 +205,7 @@ func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults * return err } - scanResults := utils.NewAuditResults() + scanResults := results.NewAuditResults() scanResults.XrayVersion = xrayVersion scanResults.ExtendedScanResults.EntitledForJas, err = jas.IsEntitledForJas(xrayManager, xrayVersion) @@ -267,11 +268,11 @@ func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults * scanCmd.performScanTasks(fileProducerConsumer, indexedFileProducerConsumer, &JasScanProducerConsumer) // Handle results - flatResults := []*utils.ScaScanResult{} + flatResults := []*results.ScaScanResult{} for _, arr := range resultsArr { for _, res := range arr { - flatResults = append(flatResults, &utils.ScaScanResult{Target: res.Target, XrayResults: []services.ScanResponse{*res.Result}}) + flatResults = append(flatResults, &results.ScaScanResult{Target: res.Target, XrayResults: []services.ScanResponse{*res.Result}}) scanResults.ExtendedScanResults.ApplicabilityScanResults = append(scanResults.ExtendedScanResults.ApplicabilityScanResults, res.ExtendedScanResults.ApplicabilityScanResults...) scanResults.ExtendedScanResults.SecretsScanResults = append(scanResults.ExtendedScanResults.SecretsScanResults, res.ExtendedScanResults.SecretsScanResults...) } @@ -410,7 +411,7 @@ func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, entitledFo return } - scanResults := utils.Results{ + scanResults := utils.ScanCommandResults{ ScaResults: []*utils.ScaScanResult{{XrayResults: []services.ScanResponse{*graphScanResults}}}, ExtendedScanResults: &utils.ExtendedScanResults{}, } diff --git a/jas/runner/jasrunner.go b/jas/runner/jasrunner.go index e94f4563..76b1362b 100644 --- a/jas/runner/jasrunner.go +++ b/jas/runner/jasrunner.go @@ -13,13 +13,14 @@ import ( "github.com/jfrog/jfrog-cli-security/jas/secrets" "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/techutils" clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/log" "golang.org/x/exp/slices" ) -func AddJasScannersTasks(securityParallelRunner *utils.SecurityParallelRunner, scanResults *utils.Results, technologiesList []techutils.Technology, directDependencies *[]string, +func AddJasScannersTasks(securityParallelRunner *utils.SecurityParallelRunner, scanResults *results.ScanCommandResults, technologiesList []techutils.Technology, directDependencies *[]string, serverDetails *config.ServerDetails, thirdPartyApplicabilityScan bool, msi string, scanner *jas.JasScanner, scanType applicability.ApplicabilityScanType, secretsScanType secrets.SecretsScanType, errHandlerFunc func(error), scansToPreform []utils.SubScanType) (err error) { if serverDetails == nil || len(serverDetails.Url) == 0 { log.Warn("To include 'Advanced Security' scan as part of the audit output, please run the 'jf c add' command before running this command.") @@ -80,7 +81,7 @@ func addModuleJasScanTask(module jfrogappsconfig.Module, scanType jasutils.JasSc return } -func runSecretsScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, extendedScanResults *utils.ExtendedScanResults, +func runSecretsScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, extendedScanResults *results.ExtendedScanResults, module jfrogappsconfig.Module, secretsScanType secrets.SecretsScanType) parallel.TaskFunc { return func(threadId int) (err error) { defer func() { @@ -97,7 +98,7 @@ func runSecretsScan(securityParallelRunner *utils.SecurityParallelRunner, scanne } } -func runIacScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, extendedScanResults *utils.ExtendedScanResults, +func runIacScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, extendedScanResults *results.ExtendedScanResults, module jfrogappsconfig.Module) parallel.TaskFunc { return func(threadId int) (err error) { defer func() { @@ -114,7 +115,7 @@ func runIacScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *j } } -func runSastScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, extendedScanResults *utils.ExtendedScanResults, +func runSastScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, extendedScanResults *results.ExtendedScanResults, module jfrogappsconfig.Module) parallel.TaskFunc { return func(threadId int) (err error) { defer func() { @@ -131,7 +132,7 @@ func runSastScan(securityParallelRunner *utils.SecurityParallelRunner, scanner * } } -func runContextualScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, scanResults *utils.Results, +func runContextualScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, scanResults *results.ScanCommandResults, module jfrogappsconfig.Module, directDependencies *[]string, thirdPartyApplicabilityScan bool, scanType applicability.ApplicabilityScanType) parallel.TaskFunc { return func(threadId int) (err error) { defer func() { diff --git a/jas/runner/jasrunner_test.go b/jas/runner/jasrunner_test.go index 6fc7f197..4ecc8ac2 100644 --- a/jas/runner/jasrunner_test.go +++ b/jas/runner/jasrunner_test.go @@ -1,15 +1,17 @@ package runner import ( - "github.com/jfrog/jfrog-cli-core/v2/common/cliutils" "os" "testing" + "github.com/jfrog/jfrog-cli-core/v2/common/cliutils" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-security/jas" "github.com/jfrog/jfrog-cli-security/jas/applicability" "github.com/jfrog/jfrog-cli-security/jas/secrets" "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "github.com/stretchr/testify/assert" @@ -36,7 +38,7 @@ func TestGetExtendedScanResults_ServerNotValid(t *testing.T) { scanner := &jas.JasScanner{} jasScanner, err := jas.CreateJasScanner(scanner, nil, &jas.FakeServerDetails) assert.NoError(t, err) - scanResults := &utils.Results{ScaResults: []*utils.ScaScanResult{{Technology: techutils.Pip, XrayResults: jas.FakeBasicXrayResults}}, ExtendedScanResults: &utils.ExtendedScanResults{}} + scanResults := &results.ScanCommandResults{ScaResults: []*results.ScaScanResult{{Technology: techutils.Pip, XrayResults: jas.FakeBasicXrayResults}}, ExtendedScanResults: &results.ExtendedScanResults{}} err = AddJasScannersTasks(securityParallelRunnerForTest, scanResults, scanResults.GetScaScannedTechnologies(), &[]string{"issueId_1_direct_dependency", "issueId_2_direct_dependency"}, nil, false, "", jasScanner, applicability.ApplicabilityScannerType, secrets.SecretsScannerType, securityParallelRunnerForTest.AddErrorToChan, utils.GetAllSupportedScans()) assert.NoError(t, err) } diff --git a/utils/results/common.go b/utils/results/common.go index 7c02504f..6a88f450 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -7,7 +7,6 @@ import ( "strings" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" @@ -412,7 +411,7 @@ func getImpactPathKey(path []services.ImpactPathNode) string { return key } -func SplitScaScanResults(results *utils.ScaScanResult) ([]services.Violation, []services.Vulnerability, []services.License) { +func SplitScaScanResults(results *ScaScanResult) ([]services.Violation, []services.Vulnerability, []services.License) { var violations []services.Violation var vulnerabilities []services.Vulnerability var licenses []services.License diff --git a/utils/results/conversion/convertor.go b/utils/results/conversion/convertor.go new file mode 100644 index 00000000..8e92a5c0 --- /dev/null +++ b/utils/results/conversion/convertor.go @@ -0,0 +1,251 @@ +package conversion + +import ( + "strconv" + "strings" + + "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/results/conversion/sarifparser" + "github.com/jfrog/jfrog-cli-security/utils/results/conversion/simplejsonparser" + "github.com/jfrog/jfrog-cli-security/utils/results/conversion/summaryparser" + "github.com/jfrog/jfrog-cli-security/utils/results/conversion/tableparser" + "github.com/jfrog/jfrog-cli-security/utils/techutils" + "github.com/jfrog/jfrog-client-go/xray/services" + "github.com/owenrumney/go-sarif/v2/sarif" +) + +type CommandResultsConvertor struct { + Params ResultConvertParams +} + +type ResultConvertParams struct { + // Control if the output should include licenses information + IncludeLicenses bool + // Control if the output should include vulnerabilities information + IncludeVulnerabilities bool + // Output will contain only the unique violations determined by the GetUniqueKey function + SimplifiedOutput bool + // Create local license violations if repo context was not provided and a license is not in this list + AllowedLicenses []string + // Convert the results to a pretty format if supported + Pretty bool + // Relevant for Sarif format since Github format does not support results without locations + AllowResultsWithoutLocations bool +} + +func NewCommandResultsConvertor(params ResultConvertParams) *CommandResultsConvertor { + return &CommandResultsConvertor{Params: params} +} + +// Parse a stream of results and convert to the desired format +type ResultsStreamFormatParser interface { + // Reset the convertor to start converting a new command results + Reset(multiScanId, xrayVersion string, entitledForJas bool) error + // Will be called for each scan target (indicating the current is done parsing and starting to parse a new scan) + ParseNewScanResultsMetadata(target string, errors error) error + // Parse SCA content to the current scan target + ParseViolations(target string, tech techutils.Technology, violations []services.Violation, applicabilityRuns ...*sarif.Run) error + ParseVulnerabilities(target string, tech techutils.Technology, vulnerabilities []services.Vulnerability, applicabilityRuns ...*sarif.Run) error + ParseLicenses(target string, tech techutils.Technology, licenses []services.License) error + // Parse JAS content to the current scan target + ParseSecrets(target string, secrets ...*sarif.Run) error + ParseIacs(target string, iacs ...*sarif.Run) error + ParseSast(target string, sast ...*sarif.Run) error +} + +func (c *CommandResultsConvertor) ConvertToSimpleJson(cmdResults *results.ScanCommandResults) (simpleJsonResults formats.SimpleJsonResults, err error) { + parser := simplejsonparser.NewCmdResultsSimpleJsonConverter(false) + err = c.parseCommandResults(parser, cmdResults) + if err != nil { + return + } + content := parser.Get() + if content == nil { + simpleJsonResults = formats.SimpleJsonResults{} + } else { + simpleJsonResults = *content + } + return +} + +func (c *CommandResultsConvertor) ConvertToSarif(cmdResults *results.ScanCommandResults) (sarifReport *sarif.Report, err error) { + parser := sarifparser.NewCmdResultsSarifConverter(c.Params.Pretty, c.Params.AllowResultsWithoutLocations) + err = c.parseCommandResults(parser, cmdResults) + if err != nil { + return + } + return parser.Get() +} + +func (c *CommandResultsConvertor) ConvertToTable(cmdResults *results.ScanCommandResults) (tableResults formats.ResultsTables, err error) { + parser := tableparser.NewCmdResultsTableConverter(c.Params.Pretty) + err = c.parseCommandResults(parser, cmdResults) + if err != nil { + return + } + content := parser.Get() + if content == nil { + tableResults = formats.ResultsTables{} + } else { + tableResults = *content + } + return +} + +func (c *CommandResultsConvertor) ConvertToSummary(cmdResults *results.ScanCommandResults) (summaryResults formats.SummaryResults, err error) { + parser := summaryparser.NewCmdResultsSummaryConverter() + err = c.parseCommandResults(parser, cmdResults) + if err != nil { + return + } + return *parser.Get(), nil +} + +func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormatParser, cmdResults *results.ScanCommandResults) (err error) { + jasEntitled := cmdResults.EntitledForJas + multipleTargets := cmdResults.HasMultipleTargets() + parser.Reset(cmdResults.MultiScanId, cmdResults.XrayVersion, jasEntitled) + for _, scan := range cmdResults.Scans { + if err = parser.ParseNewScanResultsMetadata(scan.Target, scan.Errors); err != nil { + return err + } + for _, scaResults := range scan.ScaResults { + actualTarget := scaResults.Target + if actualTarget == "" { + // If target was not provided, use the scan target + // TODO: make sure works for build-scan since its not a file + actualTarget = scan.Target + } + var applicableRuns []*sarif.Run + if jasEntitled && scan.JasResults != nil { + applicableRuns = scan.JasResults.ApplicabilityScanResults + } + vulnerabilities := scaResults.XrayResult.Vulnerabilities + if c.Params.SimplifiedOutput { + vulnerabilities = simplifyVulnerabilities(vulnerabilities, multipleTargets) + } + if len(vulnerabilities) > 0 { + if err = parser.ParseVulnerabilities(actualTarget, scaResults.Technology, vulnerabilities, applicableRuns...); err != nil { + return + } + } + violations := scaResults.XrayResult.Violations + if c.Params.SimplifiedOutput { + violations = simplifyViolations(violations, multipleTargets) + } + if len(violations) > 0 { + if err = parser.ParseViolations(actualTarget, scaResults.Technology, violations, applicableRuns...); err != nil { + return + } + } else if len(c.Params.AllowedLicenses) > 0 { + // If no violations were found, check if there are licenses that are not allowed + licViolations := results.GetViolatedLicenses(c.Params.AllowedLicenses, scaResults.XrayResult.Licenses) + if len(licViolations) > 0 { + if err = parser.ParseViolations(actualTarget, scaResults.Technology, results.GetViolatedLicenses(c.Params.AllowedLicenses, scaResults.XrayResult.Licenses)); err != nil { + return + } + } + } + if c.Params.IncludeLicenses { + if err = parser.ParseLicenses(actualTarget, scaResults.Technology, scaResults.XrayResult.Licenses); err != nil { + return + } + } + } + if !jasEntitled || scan.JasResults == nil { + continue + } + if err = parser.ParseSecrets(scan.Target, scan.JasResults.SecretsScanResults...); err != nil { + return + } + if err = parser.ParseIacs(scan.Target, scan.JasResults.IacScanResults...); err != nil { + return + } + if err = parser.ParseSast(scan.Target, scan.JasResults.SastScanResults...); err != nil { + return + } + } + return +} + +// simplifyViolations returns a new slice of services.Violations that contains only the unique violations from the input slice +// The uniqueness of the violations is determined by the GetUniqueKey function +func simplifyViolations(scanViolations []services.Violation, multipleRoots bool) []services.Violation { + var uniqueViolations = make(map[string]*services.Violation) + for _, violation := range scanViolations { + for vulnerableComponentId := range violation.Components { + vulnerableDependency, vulnerableVersion, _ := techutils.SplitComponentId(vulnerableComponentId) + packageKey := GetUniqueKey(vulnerableDependency, vulnerableVersion, violation.IssueId, len(violation.Components[vulnerableComponentId].FixedVersions) > 0) + if uniqueVulnerability, exist := uniqueViolations[packageKey]; exist { + fixedVersions := utils.UniqueUnion(uniqueVulnerability.Components[vulnerableComponentId].FixedVersions, violation.Components[vulnerableComponentId].FixedVersions...) + impactPaths := results.AppendUniqueImpactPaths(uniqueVulnerability.Components[vulnerableComponentId].ImpactPaths, violation.Components[vulnerableComponentId].ImpactPaths, multipleRoots) + uniqueViolations[packageKey].Components[vulnerableComponentId] = services.Component{ + FixedVersions: fixedVersions, + ImpactPaths: impactPaths, + } + continue + } + uniqueViolations[packageKey] = &services.Violation{ + Summary: violation.Summary, + Severity: violation.Severity, + ViolationType: violation.ViolationType, + Components: map[string]services.Component{vulnerableComponentId: violation.Components[vulnerableComponentId]}, + WatchName: violation.WatchName, + IssueId: violation.IssueId, + Cves: violation.Cves, + LicenseKey: violation.LicenseKey, + LicenseName: violation.LicenseName, + Technology: violation.Technology, + } + } + } + // convert map to slice + result := make([]services.Violation, 0, len(uniqueViolations)) + for _, v := range uniqueViolations { + result = append(result, *v) + } + return result +} + +// simplifyVulnerabilities returns a new slice of services.Vulnerability that contains only the unique vulnerabilities from the input slice +// The uniqueness of the vulnerabilities is determined by the GetUniqueKey function +func simplifyVulnerabilities(scanVulnerabilities []services.Vulnerability, multipleRoots bool) []services.Vulnerability { + var uniqueVulnerabilities = make(map[string]*services.Vulnerability) + for _, vulnerability := range scanVulnerabilities { + for vulnerableComponentId := range vulnerability.Components { + vulnerableDependency, vulnerableVersion, _ := techutils.SplitComponentId(vulnerableComponentId) + packageKey := GetUniqueKey(vulnerableDependency, vulnerableVersion, vulnerability.IssueId, len(vulnerability.Components[vulnerableComponentId].FixedVersions) > 0) + if uniqueVulnerability, exist := uniqueVulnerabilities[packageKey]; exist { + fixedVersions := utils.UniqueUnion(uniqueVulnerability.Components[vulnerableComponentId].FixedVersions, vulnerability.Components[vulnerableComponentId].FixedVersions...) + impactPaths := results.AppendUniqueImpactPaths(uniqueVulnerability.Components[vulnerableComponentId].ImpactPaths, vulnerability.Components[vulnerableComponentId].ImpactPaths, multipleRoots) + uniqueVulnerabilities[packageKey].Components[vulnerableComponentId] = services.Component{ + FixedVersions: fixedVersions, + ImpactPaths: impactPaths, + } + continue + } + uniqueVulnerabilities[packageKey] = &services.Vulnerability{ + Cves: vulnerability.Cves, + Severity: vulnerability.Severity, + Components: map[string]services.Component{vulnerableComponentId: vulnerability.Components[vulnerableComponentId]}, + IssueId: vulnerability.IssueId, + Technology: vulnerability.Technology, + ExtendedInformation: vulnerability.ExtendedInformation, + Summary: vulnerability.Summary, + } + } + } + // convert map to slice + result := make([]services.Vulnerability, 0, len(uniqueVulnerabilities)) + for _, v := range uniqueVulnerabilities { + result = append(result, *v) + } + return result +} + +// GetUniqueKey returns a unique string key of format "vulnerableDependency:vulnerableVersion:xrayID:fixVersionExist" +func GetUniqueKey(vulnerableDependency, vulnerableVersion, xrayID string, fixVersionExist bool) string { + return strings.Join([]string{vulnerableDependency, vulnerableVersion, xrayID, strconv.FormatBool(fixVersionExist)}, ":") +} \ No newline at end of file diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go new file mode 100644 index 00000000..ab825330 --- /dev/null +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -0,0 +1 @@ +package sarifparser \ No newline at end of file diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go new file mode 100644 index 00000000..683a3a0a --- /dev/null +++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go @@ -0,0 +1 @@ +package simplejsonparser \ No newline at end of file diff --git a/utils/results/conversion/summaryparser/summaryparser.go b/utils/results/conversion/summaryparser/summaryparser.go new file mode 100644 index 00000000..2a21aa42 --- /dev/null +++ b/utils/results/conversion/summaryparser/summaryparser.go @@ -0,0 +1 @@ +package summaryparser \ No newline at end of file diff --git a/utils/results/conversion/tableparser/tableparser.go b/utils/results/conversion/tableparser/tableparser.go new file mode 100644 index 00000000..70311cce --- /dev/null +++ b/utils/results/conversion/tableparser/tableparser.go @@ -0,0 +1 @@ +package tableparser \ No newline at end of file diff --git a/utils/results.go b/utils/results/results.go similarity index 84% rename from utils/results.go rename to utils/results/results.go index 3589b617..b9e036f1 100644 --- a/utils/results.go +++ b/utils/results/results.go @@ -1,4 +1,4 @@ -package utils +package results import ( "github.com/jfrog/gofrog/datastructures" @@ -9,7 +9,7 @@ import ( "github.com/owenrumney/go-sarif/v2/sarif" ) -type Results struct { +type ScanCommandResults struct { ScaResults []*ScaScanResult XrayVersion string ScansErr error @@ -19,18 +19,18 @@ type Results struct { MultiScanId string } -func NewAuditResults() *Results { - return &Results{ExtendedScanResults: &ExtendedScanResults{}} +func NewAuditResults() *ScanCommandResults { + return &ScanCommandResults{ExtendedScanResults: &ExtendedScanResults{}} } -func (r *Results) GetScaScansXrayResults() (results []services.ScanResponse) { +func (r *ScanCommandResults) GetScaScansXrayResults() (results []services.ScanResponse) { for _, scaResult := range r.ScaResults { results = append(results, scaResult.XrayResults...) } return } -func (r *Results) GetScaScannedTechnologies() []techutils.Technology { +func (r *ScanCommandResults) GetScaScannedTechnologies() []techutils.Technology { technologies := datastructures.MakeSet[techutils.Technology]() for _, scaResult := range r.ScaResults { technologies.Add(scaResult.Technology) @@ -38,7 +38,7 @@ func (r *Results) GetScaScannedTechnologies() []techutils.Technology { return technologies.ToSlice() } -func (r *Results) IsMultipleProject() bool { +func (r *ScanCommandResults) IsMultipleProject() bool { if len(r.ScaResults) == 0 { return false } @@ -51,7 +51,7 @@ func (r *Results) IsMultipleProject() bool { return true } -func (r *Results) IsScaIssuesFound() bool { +func (r *ScanCommandResults) IsScaIssuesFound() bool { for _, scan := range r.ScaResults { if scan.HasInformation() { return true @@ -60,7 +60,7 @@ func (r *Results) IsScaIssuesFound() bool { return false } -func (r *Results) getScaScanResultByTarget(target string) *ScaScanResult { +func (r *ScanCommandResults) getScaScanResultByTarget(target string) *ScaScanResult { for _, scan := range r.ScaResults { if scan.Target == target { return scan @@ -69,7 +69,7 @@ func (r *Results) getScaScanResultByTarget(target string) *ScaScanResult { return nil } -func (r *Results) IsIssuesFound() bool { +func (r *ScanCommandResults) IsIssuesFound() bool { if r.IsScaIssuesFound() { return true } @@ -81,10 +81,10 @@ func (r *Results) IsIssuesFound() bool { // Counts the total number of unique findings in the provided results. // A unique SCA finding is identified by a unique pair of vulnerability's/violation's issueId and component id or by a result returned from one of JAS scans. -func (r *Results) CountScanResultsFindings() (total int) { +func (r *ScanCommandResults) CountScanResultsFindings() (total int) { return formats.SummaryResults{Scans: r.getScanSummaryByTargets()}.GetTotalIssueCount() } -func (r *Results) GetSummary() (summary formats.SummaryResults) { +func (r *ScanCommandResults) GetSummary() (summary formats.SummaryResults) { if len(r.ScaResults) <= 1 { summary.Scans = r.getScanSummaryByTargets() return @@ -96,7 +96,7 @@ func (r *Results) GetSummary() (summary formats.SummaryResults) { } // Returns a summary for the provided targets. If no targets are provided, a summary for all targets is returned. -func (r *Results) getScanSummaryByTargets(targets ...string) (summaries []formats.ScanSummaryResult) { +func (r *ScanCommandResults) getScanSummaryByTargets(targets ...string) (summaries []formats.ScanSummaryResult) { if len(targets) == 0 { // No filter, one scan summary for all targets summaries = append(summaries, getScanSummary(r.ExtendedScanResults, r.ScaResults...)) diff --git a/utils/results_test.go b/utils/results/results_test.go similarity index 92% rename from utils/results_test.go rename to utils/results/results_test.go index a5f87048..5117f0d4 100644 --- a/utils/results_test.go +++ b/utils/results/results_test.go @@ -1,4 +1,4 @@ -package utils +package results import ( "testing" @@ -15,13 +15,13 @@ func TestGetScaScanResultByTarget(t *testing.T) { target2 := &ScaScanResult{Target: "target2"} testCases := []struct { name string - results Results + cmdResults ScanCommandResults target string expected *ScaScanResult }{ { name: "Sca scan result by target", - results: Results{ + cmdResults: ScanCommandResults{ ScaResults: []*ScaScanResult{ target1, target2, @@ -32,7 +32,7 @@ func TestGetScaScanResultByTarget(t *testing.T) { }, { name: "Sca scan result by target not found", - results: Results{ + cmdResults: ScanCommandResults{ ScaResults: []*ScaScanResult{ target1, target2, @@ -44,7 +44,7 @@ func TestGetScaScanResultByTarget(t *testing.T) { } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - result := testCase.results.getScaScanResultByTarget(testCase.target) + result := testCase.cmdResults.getScaScanResultByTarget(testCase.target) assert.Equal(t, testCase.expected, result) }) } @@ -74,21 +74,21 @@ func TestGetSummary(t *testing.T) { testCases := []struct { name string - results Results + cmdResults ScanCommandResults expected formats.SummaryResults findingCount int issueCount int }{ { name: "Empty results", - results: Results{ScaResults: []*ScaScanResult{}}, + cmdResults: ScanCommandResults{ScaResults: []*ScaScanResult{}}, expected: formats.SummaryResults{Scans: []formats.ScanSummaryResult{{}}}, findingCount: 0, issueCount: 0, }, { name: "One module result", - results: Results{ + cmdResults: ScanCommandResults{ ScaResults: []*ScaScanResult{{ Target: "target1", XrayResults: getDummyScaTestResults(true, false), @@ -119,7 +119,7 @@ func TestGetSummary(t *testing.T) { }, { name: "Multiple module results", - results: Results{ + cmdResults: ScanCommandResults{ ScaResults: []*ScaScanResult{ { Target: "target1", @@ -165,10 +165,10 @@ func TestGetSummary(t *testing.T) { } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - result := testCase.results.GetSummary() + result := testCase.cmdResults.GetSummary() assert.Equal(t, testCase.expected, result) - assert.Equal(t, testCase.findingCount, testCase.results.CountScanResultsFindings()) - assert.Equal(t, testCase.issueCount, testCase.results.GetSummary().GetTotalIssueCount()) + assert.Equal(t, testCase.findingCount, testCase.cmdResults.CountScanResultsFindings()) + assert.Equal(t, testCase.issueCount, testCase.cmdResults.GetSummary().GetTotalIssueCount()) }) } } diff --git a/utils/resultstable.go b/utils/resultstable.go index 63b2666d..26a2791a 100644 --- a/utils/resultstable.go +++ b/utils/resultstable.go @@ -38,8 +38,8 @@ const ( // In case one (or more) of the violations contains the field FailBuild set to true, CliError with exit code 3 will be returned. // Set printExtended to true to print fields with 'extended' tag. // If the scan argument is set to true, print the scan tables. -func PrintViolationsTable(violations []services.Violation, results *Results, multipleRoots, printExtended bool, scanType services.ScanType) error { - securityViolationsRows, licenseViolationsRows, operationalRiskViolationsRows, err := prepareViolations(violations, results, multipleRoots, true, true) +func PrintViolationsTable(violations []services.Violation, cmdResults *ScanCommandResults, multipleRoots, printExtended bool, scanType services.ScanType) error { + securityViolationsRows, licenseViolationsRows, operationalRiskViolationsRows, err := prepareViolations(violations, cmdResults, multipleRoots, true, true) if err != nil { return err } @@ -73,11 +73,11 @@ func PrintViolationsTable(violations []services.Violation, results *Results, mul } // Prepare violations for all non-table formats (without style or emoji) -func PrepareViolations(violations []services.Violation, results *Results, multipleRoots, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, []formats.LicenseRow, []formats.OperationalRiskViolationRow, error) { - return prepareViolations(violations, results, multipleRoots, false, simplifiedOutput) +func PrepareViolations(violations []services.Violation, cmdResults *ScanCommandResults, multipleRoots, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, []formats.LicenseRow, []formats.OperationalRiskViolationRow, error) { + return prepareViolations(violations, cmdResults, multipleRoots, false, simplifiedOutput) } -func prepareViolations(violations []services.Violation, results *Results, multipleRoots, isTable, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, []formats.LicenseRow, []formats.OperationalRiskViolationRow, error) { +func prepareViolations(violations []services.Violation, cmdResults *ScanCommandResults, multipleRoots, isTable, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, []formats.LicenseRow, []formats.OperationalRiskViolationRow, error) { if simplifiedOutput { violations = simplifyViolations(violations, multipleRoots) } @@ -92,12 +92,12 @@ func prepareViolations(violations []services.Violation, results *Results, multip switch violation.ViolationType { case formats.ViolationTypeSecurity.String(): cves := convertCves(violation.Cves) - if results.ExtendedScanResults.EntitledForJas { + if cmdResults.ExtendedScanResults.EntitledForJas { for i := range cves { - cves[i].Applicability = getCveApplicabilityField(cves[i].Id, results.ExtendedScanResults.ApplicabilityScanResults, violation.Components) + cves[i].Applicability = getCveApplicabilityField(cves[i].Id, cmdResults.ExtendedScanResults.ApplicabilityScanResults, violation.Components) } } - applicabilityStatus := getApplicableCveStatus(results.ExtendedScanResults.EntitledForJas, results.ExtendedScanResults.ApplicabilityScanResults, cves) + applicabilityStatus := getApplicableCveStatus(cmdResults.ExtendedScanResults.EntitledForJas, cmdResults.ExtendedScanResults.ApplicabilityScanResults, cves) currSeverity, err := severityutils.ParseSeverity(violation.Severity, false) if err != nil { return nil, nil, nil, err @@ -192,8 +192,8 @@ func prepareViolations(violations []services.Violation, results *Results, multip // In case multipleRoots is true, the field Component will show the root of each impact path, otherwise it will show the root's child. // Set printExtended to true to print fields with 'extended' tag. // If the scan argument is set to true, print the scan tables. -func PrintVulnerabilitiesTable(vulnerabilities []services.Vulnerability, results *Results, multipleRoots, printExtended bool, scanType services.ScanType) error { - vulnerabilitiesRows, err := prepareVulnerabilities(vulnerabilities, results, multipleRoots, true, true) +func PrintVulnerabilitiesTable(vulnerabilities []services.Vulnerability, cmdResults *ScanCommandResults, multipleRoots, printExtended bool, scanType services.ScanType) error { + vulnerabilitiesRows, err := prepareVulnerabilities(vulnerabilities, cmdResults, multipleRoots, true, true) if err != nil { return err } @@ -202,7 +202,7 @@ func PrintVulnerabilitiesTable(vulnerabilities []services.Vulnerability, results return coreutils.PrintTable(formats.ConvertToVulnerabilityScanTableRow(vulnerabilitiesRows), "Vulnerable Components", "✨ No vulnerable components were found ✨", printExtended) } var emptyTableMessage string - if len(results.ScaResults) > 0 { + if len(cmdResults.ScaResults) > 0 { emptyTableMessage = "✨ No vulnerable dependencies were found ✨" } else { emptyTableMessage = coreutils.PrintYellow("🔧 Couldn't determine a package manager or build tool used by this project 🔧") @@ -211,11 +211,11 @@ func PrintVulnerabilitiesTable(vulnerabilities []services.Vulnerability, results } // Prepare vulnerabilities for all non-table formats (without style or emoji) -func PrepareVulnerabilities(vulnerabilities []services.Vulnerability, results *Results, multipleRoots, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, error) { - return prepareVulnerabilities(vulnerabilities, results, multipleRoots, false, simplifiedOutput) +func PrepareVulnerabilities(vulnerabilities []services.Vulnerability, cmdResults *ScanCommandResults, multipleRoots, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, error) { + return prepareVulnerabilities(vulnerabilities, cmdResults, multipleRoots, false, simplifiedOutput) } -func prepareVulnerabilities(vulnerabilities []services.Vulnerability, results *Results, multipleRoots, isTable, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, error) { +func prepareVulnerabilities(vulnerabilities []services.Vulnerability, cmdResults *ScanCommandResults, multipleRoots, isTable, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, error) { if simplifiedOutput { vulnerabilities = simplifyVulnerabilities(vulnerabilities, multipleRoots) } @@ -226,12 +226,12 @@ func prepareVulnerabilities(vulnerabilities []services.Vulnerability, results *R return nil, err } cves := convertCves(vulnerability.Cves) - if results.ExtendedScanResults.EntitledForJas { + if cmdResults.ExtendedScanResults.EntitledForJas { for i := range cves { - cves[i].Applicability = getCveApplicabilityField(cves[i].Id, results.ExtendedScanResults.ApplicabilityScanResults, vulnerability.Components) + cves[i].Applicability = getCveApplicabilityField(cves[i].Id, cmdResults.ExtendedScanResults.ApplicabilityScanResults, vulnerability.Components) } } - applicabilityStatus := getApplicableCveStatus(results.ExtendedScanResults.EntitledForJas, results.ExtendedScanResults.ApplicabilityScanResults, cves) + applicabilityStatus := getApplicableCveStatus(cmdResults.ExtendedScanResults.EntitledForJas, cmdResults.ExtendedScanResults.ApplicabilityScanResults, cves) currSeverity, err := severityutils.ParseSeverity(vulnerability.Severity, false) if err != nil { return nil, err diff --git a/utils/resultwriter.go b/utils/resultwriter.go index 03aa0c9f..56982e2d 100644 --- a/utils/resultwriter.go +++ b/utils/resultwriter.go @@ -12,6 +12,7 @@ import ( "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/severityutils" "github.com/jfrog/jfrog-cli-security/utils/techutils" clientUtils "github.com/jfrog/jfrog-client-go/utils" @@ -31,8 +32,8 @@ const MissingCveScore = "0" const maxPossibleCve = 10.0 type ResultsWriter struct { - // The scan results. - results *Results + // The scan cmdResults. + cmdResults *results.ScanCommandResults // SimpleJsonError Errors to be added to output of the SimpleJson format. simpleJsonError []formats.SimpleJsonError // Format The output format. @@ -53,8 +54,8 @@ type ResultsWriter struct { messages []string } -func NewResultsWriter(scanResults *Results) *ResultsWriter { - return &ResultsWriter{results: scanResults} +func NewResultsWriter(scanResults *results.ScanCommandResults) *ResultsWriter { + return &ResultsWriter{cmdResults: scanResults} } func (rw *ResultsWriter) SetOutputFormat(f format.OutputFormat) *ResultsWriter { @@ -115,18 +116,18 @@ func (rw *ResultsWriter) PrintScanResults() error { } return PrintJson(jsonTable) case format.Json: - return PrintJson(rw.results.GetScaScansXrayResults()) + return PrintJson(rw.cmdResults.GetScaScansXrayResults()) case format.Sarif: - return PrintSarif(rw.results, rw.isMultipleRoots, rw.includeLicenses) + return PrintSarif(rw.cmdResults, rw.isMultipleRoots, rw.includeLicenses) } return nil } func (rw *ResultsWriter) printScanResultsTables() (err error) { printMessages(rw.messages) - violations, vulnerabilities, licenses := SplitScanResults(rw.results.ScaResults) - if rw.results.IsIssuesFound() { + violations, vulnerabilities, licenses := SplitScanResults(rw.cmdResults.ScaResults) + if rw.cmdResults.IsIssuesFound() { var resultsPath string - if resultsPath, err = writeJsonResults(rw.results); err != nil { + if resultsPath, err = writeJsonResults(rw.cmdResults); err != nil { return } printMessage(coreutils.PrintTitle("The full scan results are available here: ") + coreutils.PrintLink(resultsPath)) @@ -134,9 +135,9 @@ func (rw *ResultsWriter) printScanResultsTables() (err error) { log.Output() if shouldPrintTable(rw.subScansPreformed, ScaScan, rw.scanType) { if rw.includeVulnerabilities { - err = PrintVulnerabilitiesTable(vulnerabilities, rw.results, rw.isMultipleRoots, rw.printExtended, rw.scanType) + err = PrintVulnerabilitiesTable(vulnerabilities, rw.cmdResults, rw.isMultipleRoots, rw.printExtended, rw.scanType) } else { - err = PrintViolationsTable(violations, rw.results, rw.isMultipleRoots, rw.printExtended, rw.scanType) + err = PrintViolationsTable(violations, rw.cmdResults, rw.isMultipleRoots, rw.printExtended, rw.scanType) } if err != nil { return @@ -148,19 +149,19 @@ func (rw *ResultsWriter) printScanResultsTables() (err error) { } } if shouldPrintTable(rw.subScansPreformed, SecretsScan, rw.scanType) { - if err = PrintSecretsTable(rw.results.ExtendedScanResults.SecretsScanResults, rw.results.ExtendedScanResults.EntitledForJas); err != nil { + if err = PrintSecretsTable(rw.cmdResults.ExtendedScanResults.SecretsScanResults, rw.cmdResults.ExtendedScanResults.EntitledForJas); err != nil { return } } if shouldPrintTable(rw.subScansPreformed, IacScan, rw.scanType) { - if err = PrintIacTable(rw.results.ExtendedScanResults.IacScanResults, rw.results.ExtendedScanResults.EntitledForJas); err != nil { + if err = PrintIacTable(rw.cmdResults.ExtendedScanResults.IacScanResults, rw.cmdResults.ExtendedScanResults.EntitledForJas); err != nil { return } } if !shouldPrintTable(rw.subScansPreformed, SastScan, rw.scanType) { return nil } - return PrintSastTable(rw.results.ExtendedScanResults.SastScanResults, rw.results.ExtendedScanResults.EntitledForJas) + return PrintSastTable(rw.cmdResults.ExtendedScanResults.SastScanResults, rw.cmdResults.ExtendedScanResults.EntitledForJas) } func shouldPrintTable(requestedScans []SubScanType, subScan SubScanType, scanType services.ScanType) bool { @@ -183,32 +184,32 @@ func printMessage(message string) { log.Output("💬" + message) } -func GenereateSarifReportFromResults(results *Results, isMultipleRoots, includeLicenses bool, allowedLicenses []string) (report *sarif.Report, err error) { +func GenereateSarifReportFromResults(cmdResults *results.ScanCommandResults, isMultipleRoots, includeLicenses bool, allowedLicenses []string) (report *sarif.Report, err error) { report, err = sarifutils.NewReport() if err != nil { return } - xrayRun, err := convertXrayResponsesToSarifRun(results, isMultipleRoots, includeLicenses, allowedLicenses) + xrayRun, err := convertXrayResponsesToSarifRun(cmdResults, isMultipleRoots, includeLicenses, allowedLicenses) if err != nil { return } report.Runs = append(report.Runs, xrayRun) - report.Runs = append(report.Runs, results.ExtendedScanResults.ApplicabilityScanResults...) - report.Runs = append(report.Runs, results.ExtendedScanResults.IacScanResults...) - report.Runs = append(report.Runs, results.ExtendedScanResults.SecretsScanResults...) - report.Runs = append(report.Runs, results.ExtendedScanResults.SastScanResults...) + report.Runs = append(report.Runs, cmdResults.ExtendedScanResults.ApplicabilityScanResults...) + report.Runs = append(report.Runs, cmdResults.ExtendedScanResults.IacScanResults...) + report.Runs = append(report.Runs, cmdResults.ExtendedScanResults.SecretsScanResults...) + report.Runs = append(report.Runs, cmdResults.ExtendedScanResults.SastScanResults...) return } -func convertXrayResponsesToSarifRun(results *Results, isMultipleRoots, includeLicenses bool, allowedLicenses []string) (run *sarif.Run, err error) { - xrayJson, err := ConvertXrayScanToSimpleJson(results, isMultipleRoots, includeLicenses, true, allowedLicenses) +func convertXrayResponsesToSarifRun(cmdResults *results.ScanCommandResults, isMultipleRoots, includeLicenses bool, allowedLicenses []string) (run *sarif.Run, err error) { + xrayJson, err := ConvertXrayScanToSimpleJson(cmdResults, isMultipleRoots, includeLicenses, true, allowedLicenses) if err != nil { return } xrayRun := sarif.NewRunWithInformationURI("JFrog Xray SCA", BaseDocumentationURL+"sca") - xrayRun.Tool.Driver.Version = &results.XrayVersion + xrayRun.Tool.Driver.Version = &cmdResults.XrayVersion if len(xrayJson.Vulnerabilities) > 0 || len(xrayJson.SecurityViolations) > 0 || len(xrayJson.LicensesViolations) > 0 { if err = extractXrayIssuesToSarifRun(xrayRun, xrayJson); err != nil { return @@ -356,11 +357,11 @@ func addXrayRule(ruleId, ruleDescription, maxCveScore, summary, markdownDescript }) } -func ConvertXrayScanToSimpleJson(results *Results, isMultipleRoots, includeLicenses, simplifiedOutput bool, allowedLicenses []string) (formats.SimpleJsonResults, error) { - violations, vulnerabilities, licenses := SplitScanResults(results.ScaResults) +func ConvertXrayScanToSimpleJson(cmdResults *results.ScanCommandResults, isMultipleRoots, includeLicenses, simplifiedOutput bool, allowedLicenses []string) (formats.SimpleJsonResults, error) { + violations, vulnerabilities, licenses := SplitScanResults(cmdResults.ScaResults) jsonTable := formats.SimpleJsonResults{} if len(vulnerabilities) > 0 { - vulJsonTable, err := PrepareVulnerabilities(vulnerabilities, results, isMultipleRoots, simplifiedOutput) + vulJsonTable, err := PrepareVulnerabilities(vulnerabilities, cmdResults, isMultipleRoots, simplifiedOutput) if err != nil { return formats.SimpleJsonResults{}, err } @@ -377,7 +378,7 @@ func ConvertXrayScanToSimpleJson(results *Results, isMultipleRoots, includeLicen jsonTable.LicensesViolations = GetViolatedLicenses(allowedLicenses, licJsonTable) } if len(violations) > 0 { - secViolationsJsonTable, licViolationsJsonTable, opRiskViolationsJsonTable, err := PrepareViolations(violations, results, isMultipleRoots, simplifiedOutput) + secViolationsJsonTable, licViolationsJsonTable, opRiskViolationsJsonTable, err := PrepareViolations(violations, cmdResults, isMultipleRoots, simplifiedOutput) if err != nil { return formats.SimpleJsonResults{}, err } @@ -385,7 +386,7 @@ func ConvertXrayScanToSimpleJson(results *Results, isMultipleRoots, includeLicen jsonTable.LicensesViolations = licViolationsJsonTable jsonTable.OperationalRiskViolations = opRiskViolationsJsonTable } - jsonTable.MultiScanId = results.MultiScanId + jsonTable.MultiScanId = cmdResults.MultiScanId return jsonTable, nil } @@ -402,18 +403,18 @@ func GetViolatedLicenses(allowedLicenses []string, licenses []formats.LicenseRow } func (rw *ResultsWriter) convertScanToSimpleJson() (formats.SimpleJsonResults, error) { - jsonTable, err := ConvertXrayScanToSimpleJson(rw.results, rw.isMultipleRoots, rw.includeLicenses, false, nil) + jsonTable, err := ConvertXrayScanToSimpleJson(rw.cmdResults, rw.isMultipleRoots, rw.includeLicenses, false, nil) if err != nil { return formats.SimpleJsonResults{}, err } - if len(rw.results.ExtendedScanResults.SecretsScanResults) > 0 { - jsonTable.Secrets = PrepareSecrets(rw.results.ExtendedScanResults.SecretsScanResults) + if len(rw.cmdResults.ExtendedScanResults.SecretsScanResults) > 0 { + jsonTable.Secrets = PrepareSecrets(rw.cmdResults.ExtendedScanResults.SecretsScanResults) } - if len(rw.results.ExtendedScanResults.IacScanResults) > 0 { - jsonTable.Iacs = PrepareIacs(rw.results.ExtendedScanResults.IacScanResults) + if len(rw.cmdResults.ExtendedScanResults.IacScanResults) > 0 { + jsonTable.Iacs = PrepareIacs(rw.cmdResults.ExtendedScanResults.IacScanResults) } - if len(rw.results.ExtendedScanResults.SastScanResults) > 0 { - jsonTable.Sast = PrepareSast(rw.results.ExtendedScanResults.SastScanResults) + if len(rw.cmdResults.ExtendedScanResults.SastScanResults) > 0 { + jsonTable.Sast = PrepareSast(rw.cmdResults.ExtendedScanResults.SastScanResults) } jsonTable.Errors = rw.simpleJsonError @@ -503,7 +504,7 @@ func findMaxCVEScore(cves []formats.CveRow) (string, error) { } // Splits scan responses into aggregated lists of violations, vulnerabilities and licenses. -func SplitScanResults(results []*ScaScanResult) ([]services.Violation, []services.Vulnerability, []services.License) { +func SplitScanResults(results []*results.ScaScanResult) ([]services.Violation, []services.Vulnerability, []services.License) { var violations []services.Violation var vulnerabilities []services.Vulnerability var licenses []services.License @@ -517,7 +518,7 @@ func SplitScanResults(results []*ScaScanResult) ([]services.Violation, []service return violations, vulnerabilities, licenses } -func writeJsonResults(results *Results) (resultsPath string, err error) { +func writeJsonResults(cmdResults *results.ScanCommandResults) (resultsPath string, err error) { out, err := fileutils.CreateTempFile() if errorutils.CheckError(err) != nil { return @@ -528,7 +529,7 @@ func writeJsonResults(results *Results) (resultsPath string, err error) { err = e } }() - bytesRes, err := json.Marshal(&results) + bytesRes, err := json.Marshal(&cmdResults) if errorutils.CheckError(err) != nil { return } @@ -554,8 +555,8 @@ func PrintJson(output interface{}) error { return nil } -func PrintSarif(results *Results, isMultipleRoots, includeLicenses bool) error { - sarifReport, err := GenereateSarifReportFromResults(results, isMultipleRoots, includeLicenses, nil) +func PrintSarif(cmdResults *results.ScanCommandResults, isMultipleRoots, includeLicenses bool) error { + sarifReport, err := GenereateSarifReportFromResults(cmdResults, isMultipleRoots, includeLicenses, nil) if err != nil { return err } diff --git a/utils/xsc/analyticsmetrics.go b/utils/xsc/analyticsmetrics.go index 178150c6..8e6c253f 100644 --- a/utils/xsc/analyticsmetrics.go +++ b/utils/xsc/analyticsmetrics.go @@ -9,7 +9,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-core/v2/utils/usage" "github.com/jfrog/jfrog-cli-security/jas" - "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/results" clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/log" "github.com/jfrog/jfrog-client-go/xsc" @@ -157,7 +157,7 @@ func (ams *AnalyticsMetricsService) GetGeneralEvent(msi string) (*xscservices.Xs return event, err } -func (ams *AnalyticsMetricsService) CreateXscAnalyticsGeneralEventFinalizeFromAuditResults(auditResults *utils.Results) *xscservices.XscAnalyticsGeneralEventFinalize { +func (ams *AnalyticsMetricsService) CreateXscAnalyticsGeneralEventFinalizeFromAuditResults(auditResults *results.ScanCommandResults) *xscservices.XscAnalyticsGeneralEventFinalize { totalDuration := time.Since(ams.GetStartTime()) eventStatus := xscservices.Completed if auditResults.ScansErr != nil { diff --git a/utils/xsc/analyticsmetrics_test.go b/utils/xsc/analyticsmetrics_test.go index a839a9ce..3f7cb2cd 100644 --- a/utils/xsc/analyticsmetrics_test.go +++ b/utils/xsc/analyticsmetrics_test.go @@ -9,6 +9,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-client-go/utils/tests" "github.com/jfrog/jfrog-client-go/xray/services" xscservices "github.com/jfrog/jfrog-client-go/xsc/services" @@ -77,10 +78,10 @@ func TestAnalyticsMetricsService_createAuditResultsFromXscAnalyticsBasicGeneralE usageCallback := tests.SetEnvWithCallbackAndAssert(t, coreutils.ReportUsage, "true") defer usageCallback() vulnerabilities := []services.Vulnerability{{IssueId: "XRAY-ID", Cves: []services.Cve{{Id: "CVE-123"}}, Components: map[string]services.Component{"issueId_2_direct_dependency": {}}}} - scaResults := []*utils.ScaScanResult{{XrayResults: []services.ScanResponse{{Vulnerabilities: vulnerabilities}}}} - auditResults := utils.Results{ + scaResults := []*results.ScaScanResult{{XrayResults: []services.ScanResponse{{Vulnerabilities: vulnerabilities}}}} + auditResults := results.ScanCommandResults{ ScaResults: scaResults, - ExtendedScanResults: &utils.ExtendedScanResults{ + ExtendedScanResults: &results.ExtendedScanResults{ ApplicabilityScanResults: []*sarif.Run{sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyPassingResult("applic_CVE-123"))}, SecretsScanResults: []*sarif.Run{ sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("", 0, 0, 0, 0, ""))), @@ -98,13 +99,13 @@ func TestAnalyticsMetricsService_createAuditResultsFromXscAnalyticsBasicGeneralE } testStruct := []struct { name string - auditResults *utils.Results + auditResults *results.ScanCommandResults want xscservices.XscAnalyticsBasicGeneralEvent }{ - {name: "No audit results", auditResults: &utils.Results{}, want: xscservices.XscAnalyticsBasicGeneralEvent{EventStatus: xscservices.Completed}}, + {name: "No audit results", auditResults: &results.ScanCommandResults{}, want: xscservices.XscAnalyticsBasicGeneralEvent{EventStatus: xscservices.Completed}}, {name: "Valid audit result", auditResults: &auditResults, want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 7, EventStatus: xscservices.Completed}}, - {name: "Scan failed because jas errors.", auditResults: &utils.Results{ScansErr: errors.New("jas error"), ScaResults: scaResults}, want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 1, EventStatus: xscservices.Failed}}, - {name: "Scan failed because sca errors.", auditResults: &utils.Results{ScansErr: errors.New("sca error")}, want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 0, EventStatus: xscservices.Failed}}, + {name: "Scan failed because jas errors.", auditResults: &results.ScanCommandResults{ScansErr: errors.New("jas error"), ScaResults: scaResults}, want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 1, EventStatus: xscservices.Failed}}, + {name: "Scan failed because sca errors.", auditResults: &results.ScanCommandResults{ScansErr: errors.New("sca error")}, want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 0, EventStatus: xscservices.Failed}}, } mockServer, serverDetails := utils.XscServer(t, xscservices.AnalyticsMetricsMinXscVersion) defer mockServer.Close() From 9f129e49b89e73f8dcc3c3ee137aa1104087460f Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 30 Jun 2024 17:34:27 +0300 Subject: [PATCH 05/82] add parsers --- utils/formats/conversion.go | 228 +++++--- utils/formats/table.go | 13 +- utils/results/conversion/convertor.go | 2 +- .../conversion/sarifparser/sarifparser.go | 387 +++++++++++++- .../sarifparser/sarifparser_test.go | 206 +++++++ .../simplejsonparser/simplejsonparser.go | 449 +++++++++++++++- .../simplejsonparser/simplejsonparser_test.go | 505 ++++++++++++++++++ .../conversion/summaryparser/summaryparser.go | 215 +++++++- .../summaryparser/summaryparser_test.go | 166 ++++++ .../conversion/tableparser/tableparser.go | 69 ++- .../output}/securityJobSummary.go | 13 +- .../output}/securityJobSummary_test.go | 2 +- utils/results/results.go | 433 +++++++++++---- utils/resultstable_test.go | 15 - utils/resultwriter.go | 4 - utils/utils.go | 51 ++ 16 files changed, 2557 insertions(+), 201 deletions(-) create mode 100644 utils/results/conversion/sarifparser/sarifparser_test.go create mode 100644 utils/results/conversion/simplejsonparser/simplejsonparser_test.go create mode 100644 utils/results/conversion/summaryparser/summaryparser_test.go rename utils/{ => results/output}/securityJobSummary.go (96%) rename utils/{ => results/output}/securityJobSummary_test.go (99%) diff --git a/utils/formats/conversion.go b/utils/formats/conversion.go index 8a602869..6ec0764a 100644 --- a/utils/formats/conversion.go +++ b/utils/formats/conversion.go @@ -5,9 +5,87 @@ import ( "strings" ) -func ConvertToVulnerabilityTableRow(rows []VulnerabilityOrViolationRow) (tableRows []vulnerabilityTableRow) { +func ConvertSecurityTableRowToScanTableRow(tableRows []VulnerabilityTableRow) (scanTableRows []vulnerabilityScanTableRow) { + for i := range tableRows { + scanTableRows = append(scanTableRows, vulnerabilityScanTableRow{ + severity: tableRows[i].severity, + severityNumValue: tableRows[i].severityNumValue, + applicable: tableRows[i].applicable, + impactedPackageName: tableRows[i].impactedDependencyName, + impactedPackageVersion: tableRows[i].impactedDependencyVersion, + ImpactedPackageType: tableRows[i].impactedDependencyType, + fixedVersions: tableRows[i].fixedVersions, + directPackages: convertToComponentScanTableRow(tableRows[i].directDependencies), + cves: tableRows[i].cves, + issueId: tableRows[i].issueId, + }) + } + return +} + +func ConvertLicenseViolationTableRowToScanTableRow(tableRows []licenseViolationTableRow) (scanTableRows []licenseViolationScanTableRow) { + for i := range tableRows { + scanTableRows = append(scanTableRows, licenseViolationScanTableRow{ + licenseKey: tableRows[i].licenseKey, + severity: tableRows[i].severity, + severityNumValue: tableRows[i].severityNumValue, + impactedPackageName: tableRows[i].impactedDependencyName, + impactedPackageVersion: tableRows[i].impactedDependencyVersion, + impactedDependencyType: tableRows[i].impactedDependencyType, + directDependencies: convertToComponentScanTableRow(tableRows[i].directDependencies), + }) + } + return +} + +func ConvertOperationalRiskTableRowToScanTableRow(tableRows []operationalRiskViolationTableRow) (scanTableRows []operationalRiskViolationScanTableRow) { + for i := range tableRows { + scanTableRows = append(scanTableRows, operationalRiskViolationScanTableRow{ + Severity: tableRows[i].Severity, + severityNumValue: tableRows[i].severityNumValue, + impactedPackageName: tableRows[i].impactedDependencyName, + impactedPackageVersion: tableRows[i].impactedDependencyVersion, + impactedDependencyType: tableRows[i].impactedDependencyType, + directDependencies: convertToComponentScanTableRow(tableRows[i].directDependencies), + isEol: tableRows[i].isEol, + cadence: tableRows[i].cadence, + commits: tableRows[i].Commits, + committers: tableRows[i].committers, + newerVersions: tableRows[i].newerVersions, + latestVersion: tableRows[i].latestVersion, + riskReason: tableRows[i].riskReason, + eolMessage: tableRows[i].eolMessage, + }) + } + return +} + +func ConvertLicenseTableRowToScanTableRow(tableRows []licenseTableRow) (scanTableRows []licenseScanTableRow) { + for i := range tableRows { + scanTableRows = append(scanTableRows, licenseScanTableRow{ + licenseKey: tableRows[i].licenseKey, + directDependencies: convertToComponentScanTableRow(tableRows[i].directDependencies), + impactedPackageName: tableRows[i].impactedDependencyName, + impactedPackageVersion: tableRows[i].impactedDependencyVersion, + impactedDependencyType: tableRows[i].impactedDependencyType, + }) + } + return +} + +func convertToComponentScanTableRow(rows []directDependenciesTableRow) (tableRows []directPackagesTableRow) { + for i := range rows { + tableRows = append(tableRows, directPackagesTableRow{ + name: rows[i].name, + version: rows[i].version, + }) + } + return +} + +func ConvertToVulnerabilityTableRow(rows []VulnerabilityOrViolationRow) (tableRows []VulnerabilityTableRow) { for i := range rows { - tableRows = append(tableRows, vulnerabilityTableRow{ + tableRows = append(tableRows, VulnerabilityTableRow{ severity: rows[i].Severity, severityNumValue: rows[i].SeverityNumValue, applicable: rows[i].Applicable, @@ -23,23 +101,23 @@ func ConvertToVulnerabilityTableRow(rows []VulnerabilityOrViolationRow) (tableRo return } -func ConvertToVulnerabilityScanTableRow(rows []VulnerabilityOrViolationRow) (tableRows []vulnerabilityScanTableRow) { - for i := range rows { - tableRows = append(tableRows, vulnerabilityScanTableRow{ - severity: rows[i].Severity, - severityNumValue: rows[i].SeverityNumValue, - applicable: rows[i].Applicable, - impactedPackageName: rows[i].ImpactedDependencyName, - impactedPackageVersion: rows[i].ImpactedDependencyVersion, - ImpactedPackageType: rows[i].ImpactedDependencyType, - fixedVersions: strings.Join(rows[i].FixedVersions, "\n"), - directPackages: convertToComponentScanTableRow(rows[i].Components), - cves: convertToCveTableRow(rows[i].Cves), - issueId: rows[i].IssueId, - }) - } - return -} +// func ConvertToVulnerabilityScanTableRow(rows []VulnerabilityOrViolationRow) (tableRows []vulnerabilityScanTableRow) { +// for i := range rows { +// tableRows = append(tableRows, vulnerabilityScanTableRow{ +// severity: rows[i].Severity, +// severityNumValue: rows[i].SeverityNumValue, +// applicable: rows[i].Applicable, +// impactedPackageName: rows[i].ImpactedDependencyName, +// impactedPackageVersion: rows[i].ImpactedDependencyVersion, +// ImpactedPackageType: rows[i].ImpactedDependencyType, +// fixedVersions: strings.Join(rows[i].FixedVersions, "\n"), +// directPackages: convertToComponentScanTableRow(rows[i].Components), +// cves: convertToCveTableRow(rows[i].Cves), +// issueId: rows[i].IssueId, +// }) +// } +// return +// } func ConvertToLicenseViolationTableRow(rows []LicenseRow) (tableRows []licenseViolationTableRow) { for i := range rows { @@ -56,20 +134,20 @@ func ConvertToLicenseViolationTableRow(rows []LicenseRow) (tableRows []licenseVi return } -func ConvertToLicenseViolationScanTableRow(rows []LicenseRow) (tableRows []licenseViolationScanTableRow) { - for i := range rows { - tableRows = append(tableRows, licenseViolationScanTableRow{ - licenseKey: rows[i].LicenseKey, - severity: rows[i].Severity, - severityNumValue: rows[i].SeverityNumValue, - impactedPackageName: rows[i].ImpactedDependencyName, - impactedPackageVersion: rows[i].ImpactedDependencyVersion, - impactedDependencyType: rows[i].ImpactedDependencyType, - directDependencies: convertToComponentScanTableRow(rows[i].Components), - }) - } - return -} +// func ConvertToLicenseViolationScanTableRow(rows []LicenseRow) (tableRows []licenseViolationScanTableRow) { +// for i := range rows { +// tableRows = append(tableRows, licenseViolationScanTableRow{ +// licenseKey: rows[i].LicenseKey, +// severity: rows[i].Severity, +// severityNumValue: rows[i].SeverityNumValue, +// impactedPackageName: rows[i].ImpactedDependencyName, +// impactedPackageVersion: rows[i].ImpactedDependencyVersion, +// impactedDependencyType: rows[i].ImpactedDependencyType, +// directDependencies: convertToComponentScanTableRow(rows[i].Components), +// }) +// } +// return +// } func ConvertToLicenseTableRow(rows []LicenseRow) (tableRows []licenseTableRow) { for i := range rows { @@ -84,18 +162,18 @@ func ConvertToLicenseTableRow(rows []LicenseRow) (tableRows []licenseTableRow) { return } -func ConvertToLicenseScanTableRow(rows []LicenseRow) (tableRows []licenseScanTableRow) { - for i := range rows { - tableRows = append(tableRows, licenseScanTableRow{ - licenseKey: rows[i].LicenseKey, - impactedPackageName: rows[i].ImpactedDependencyName, - impactedPackageVersion: rows[i].ImpactedDependencyVersion, - impactedDependencyType: rows[i].ImpactedDependencyType, - directDependencies: convertToComponentScanTableRow(rows[i].Components), - }) - } - return -} +// func ConvertToLicenseScanTableRow(rows []LicenseRow) (tableRows []licenseScanTableRow) { +// for i := range rows { +// tableRows = append(tableRows, licenseScanTableRow{ +// licenseKey: rows[i].LicenseKey, +// impactedPackageName: rows[i].ImpactedDependencyName, +// impactedPackageVersion: rows[i].ImpactedDependencyVersion, +// impactedDependencyType: rows[i].ImpactedDependencyType, +// directDependencies: convertToComponentScanTableRow(rows[i].Components), +// }) +// } +// return +// } func ConvertToOperationalRiskViolationTableRow(rows []OperationalRiskViolationRow) (tableRows []operationalRiskViolationTableRow) { for i := range rows { @@ -119,27 +197,27 @@ func ConvertToOperationalRiskViolationTableRow(rows []OperationalRiskViolationRo return } -func ConvertToOperationalRiskViolationScanTableRow(rows []OperationalRiskViolationRow) (tableRows []operationalRiskViolationScanTableRow) { - for i := range rows { - tableRows = append(tableRows, operationalRiskViolationScanTableRow{ - Severity: rows[i].Severity, - severityNumValue: rows[i].SeverityNumValue, - impactedPackageName: rows[i].ImpactedDependencyName, - impactedPackageVersion: rows[i].ImpactedDependencyVersion, - impactedDependencyType: rows[i].ImpactedDependencyType, - directDependencies: convertToComponentScanTableRow(rows[i].Components), - isEol: rows[i].IsEol, - cadence: rows[i].Cadence, - commits: rows[i].Commits, - committers: rows[i].Committers, - newerVersions: rows[i].NewerVersions, - latestVersion: rows[i].LatestVersion, - riskReason: rows[i].RiskReason, - eolMessage: rows[i].EolMessage, - }) - } - return -} +// func ConvertToOperationalRiskViolationScanTableRow(rows []OperationalRiskViolationRow) (tableRows []operationalRiskViolationScanTableRow) { +// for i := range rows { +// tableRows = append(tableRows, operationalRiskViolationScanTableRow{ +// Severity: rows[i].Severity, +// severityNumValue: rows[i].SeverityNumValue, +// impactedPackageName: rows[i].ImpactedDependencyName, +// impactedPackageVersion: rows[i].ImpactedDependencyVersion, +// impactedDependencyType: rows[i].ImpactedDependencyType, +// directDependencies: convertToComponentScanTableRow(rows[i].Components), +// isEol: rows[i].IsEol, +// cadence: rows[i].Cadence, +// commits: rows[i].Commits, +// committers: rows[i].Committers, +// newerVersions: rows[i].NewerVersions, +// latestVersion: rows[i].LatestVersion, +// riskReason: rows[i].RiskReason, +// eolMessage: rows[i].EolMessage, +// }) +// } +// return +// } func ConvertToSecretsTableRow(rows []SourceCodeRow) (tableRows []secretsTableRow) { for i := range rows { @@ -175,15 +253,15 @@ func convertToComponentTableRow(rows []ComponentRow) (tableRows []directDependen return } -func convertToComponentScanTableRow(rows []ComponentRow) (tableRows []directPackagesTableRow) { - for i := range rows { - tableRows = append(tableRows, directPackagesTableRow{ - name: rows[i].Name, - version: rows[i].Version, - }) - } - return -} +// func convertToComponentScanTableRow(rows []ComponentRow) (tableRows []directPackagesTableRow) { +// for i := range rows { +// tableRows = append(tableRows, directPackagesTableRow{ +// name: rows[i].Name, +// version: rows[i].Version, +// }) +// } +// return +// } func convertToCveTableRow(rows []CveRow) (tableRows []cveTableRow) { for i := range rows { diff --git a/utils/formats/table.go b/utils/formats/table.go index fc9486d9..23704767 100644 --- a/utils/formats/table.go +++ b/utils/formats/table.go @@ -4,8 +4,19 @@ package formats // Annotations are as described in the tableutils.PrintTable description. // Use the conversion methods in this package to convert from the API structs to the table structs. +type ResultsTables struct { + SecurityVulnerabilitiesTable []VulnerabilityTableRow + LicensesTable []licenseTableRow + LicenseViolationsTable []licenseViolationTableRow + OperationalRiskViolationsTable []operationalRiskViolationTableRow + IacTable []iacOrSastTableRow + SastTable []iacOrSastTableRow + SecretsTable []secretsTableRow + Errors []error +} + // Used for vulnerabilities and security violations -type vulnerabilityTableRow struct { +type VulnerabilityTableRow struct { severity string `col-name:"Severity"` applicable string `col-name:"Contextual\nAnalysis" omitempty:"true"` // For sorting diff --git a/utils/results/conversion/convertor.go b/utils/results/conversion/convertor.go index 8e92a5c0..c77b7e93 100644 --- a/utils/results/conversion/convertor.go +++ b/utils/results/conversion/convertor.go @@ -108,7 +108,7 @@ func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormat multipleTargets := cmdResults.HasMultipleTargets() parser.Reset(cmdResults.MultiScanId, cmdResults.XrayVersion, jasEntitled) for _, scan := range cmdResults.Scans { - if err = parser.ParseNewScanResultsMetadata(scan.Target, scan.Errors); err != nil { + if err = parser.ParseNewScanResultsMetadata(scan.Target, scan.Error); err != nil { return err } for _, scaResults := range scan.ScaResults { diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index ab825330..bc899c9c 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -1 +1,386 @@ -package sarifparser \ No newline at end of file +package sarifparser + +import ( + "fmt" + "strings" + + "github.com/jfrog/gofrog/datastructures" + "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/severityutils" + "github.com/jfrog/jfrog-cli-security/utils/techutils" + "github.com/jfrog/jfrog-client-go/xray/services" + "github.com/owenrumney/go-sarif/v2/sarif" +) + +const ( + ScaToolName = "JFrog Xray SCA" +) + +type CmdResultsSarifConverter struct { + // Add contextual analysis results to the Sarif report + withContextualAnalysis bool + // Pretty print the output text for Github Issues support + pretty bool + // Current stream parse cache information + current *sarif.Report + scaCurrentRun *sarif.Run + currentApplicableRuns *datastructures.Set[*sarif.Run] + // General information on the current command results + entitledForJas bool + xrayVersion string +} + +func NewCmdResultsSarifConverter(pretty, withContextualAnalysis bool) *CmdResultsSarifConverter { + return &CmdResultsSarifConverter{pretty: pretty, withContextualAnalysis: withContextualAnalysis} +} + +func (sc *CmdResultsSarifConverter) Get() (*sarif.Report, error) { + // Return the current report + if sc.current == nil { + return sarifutils.NewReport() + } + // Flush the current run + sc.ParseNewScanResultsMetadata("", nil) + return sc.current, nil +} + +func (sc *CmdResultsSarifConverter) Reset(_, xrayVersion string, entitledForJas bool) (err error) { + sc.current, err = sarifutils.NewReport() + if err != nil { + return + } + sc.currentApplicableRuns = datastructures.MakeSet[*sarif.Run]() + sc.scaCurrentRun = nil + + sc.xrayVersion = xrayVersion + sc.entitledForJas = entitledForJas + return +} + +func (sc *CmdResultsSarifConverter) ParseNewScanResultsMetadata(target string, errors error) (err error) { + if sc.current == nil { + return results.ConvertorResetErr + } + if sc.scaCurrentRun != nil { + sc.current.Runs = append(sc.current.Runs, sc.scaCurrentRun) + if sc.withContextualAnalysis { + sc.current.Runs = append(sc.current.Runs, sc.currentApplicableRuns.ToSlice()...) + } + } + sc.scaCurrentRun = sarif.NewRunWithInformationURI(ScaToolName, utils.BaseDocumentationURL+"sca") + sc.scaCurrentRun.Tool.Driver.Version = &sc.xrayVersion + return +} + +func (sc *CmdResultsSarifConverter) ParseViolations(target string, tech techutils.Technology, violations []services.Violation, applicabilityRuns ...*sarif.Run) (err error) { + if sc.current == nil { + return results.ConvertorResetErr + } + if sc.scaCurrentRun == nil { + return results.ConvertorNewScanErr + } + sarifResults, sarifRules, err := PrepareSarifScaViolations(target, sc.scaCurrentRun, sc.pretty, sc.entitledForJas, violations, applicabilityRuns...) + if err != nil || len(sarifRules) == 0 || len(sarifResults) == 0 { + return + } + sc.addScaResultsToCurrentRun(sarifRules, sarifResults...) + if !sc.entitledForJas { + return + } + for _, run := range applicabilityRuns { + sc.currentApplicableRuns.Add(run) + } + return +} + +func (sc *CmdResultsSarifConverter) ParseVulnerabilities(target string, tech techutils.Technology, vulnerabilities []services.Vulnerability, applicabilityRuns ...*sarif.Run) (err error) { + if sc.current == nil { + return results.ConvertorResetErr + } + if sc.scaCurrentRun == nil { + return results.ConvertorNewScanErr + } + sarifResults, sarifRules, err := PrepareSarifScaVulnerabilities(target, vulnerabilities, sc.pretty, sc.entitledForJas, applicabilityRuns...) + if err != nil || len(sarifRules) == 0 || len(sarifResults) == 0 { + return + } + sc.addScaResultsToCurrentRun(sarifRules, sarifResults...) + if !sc.entitledForJas { + return + } + for _, run := range applicabilityRuns { + sc.currentApplicableRuns.Add(run) + } + return +} + +func (sc *CmdResultsSarifConverter) ParseLicenses(target string, tech techutils.Technology, licenses []services.License) (err error) { + // Not supported in Sarif format + return +} + +func (sc *CmdResultsSarifConverter) ParseSecrets(_ string, secrets ...*sarif.Run) (err error) { + if !sc.entitledForJas { + return + } + if sc.current == nil { + return results.ConvertorResetErr + } + sc.current.Runs = append(sc.current.Runs, secrets...) + return +} + +func (sc *CmdResultsSarifConverter) ParseIacs(_ string, iacs ...*sarif.Run) (err error) { + if !sc.entitledForJas { + return + } + if sc.current == nil { + return results.ConvertorResetErr + } + sc.current.Runs = append(sc.current.Runs, iacs...) + return +} + +func (sc *CmdResultsSarifConverter) ParseSast(_ string, sast ...*sarif.Run) (err error) { + if !sc.entitledForJas { + return + } + if sc.current == nil { + return results.ConvertorResetErr + } + sc.current.Runs = append(sc.current.Runs, sast...) + return +} + +func (sc *CmdResultsSarifConverter) addScaResultsToCurrentRun(rules map[string]*sarif.ReportingDescriptor, results ...*sarif.Result) { + for _, rule := range rules { + // This method will add the rule only if it doesn't exist + sc.scaCurrentRun.Tool.Driver.AddRule(rule) + } + for _, result := range results { + sc.scaCurrentRun.AddResult(result) + } +} + +func PrepareSarifScaViolations(target string, run *sarif.Run, pretty, entitledForJas bool, violations []services.Violation, applicabilityRuns ...*sarif.Run) ([]*sarif.Result, map[string]*sarif.ReportingDescriptor, error) { + var sarifResults []*sarif.Result + var rules map[string]*sarif.ReportingDescriptor + err := results.PrepareScaViolations( + target, + violations, + pretty, + entitledForJas, + applicabilityRuns, + addSarifScaSecurityViolation(&sarifResults, &rules), + addSarifScaLicenseViolation(&sarifResults, &rules), + // Operational risks violations are not supported in Sarif format + nil, + ) + return sarifResults, rules, err +} + +func PrepareSarifScaVulnerabilities(target string, vulnerabilities []services.Vulnerability, pretty, entitledForJas bool, applicabilityRuns ...*sarif.Run) ([]*sarif.Result, map[string]*sarif.ReportingDescriptor, error) { + var sarifResults []*sarif.Result + var rules map[string]*sarif.ReportingDescriptor + err := results.PrepareScaVulnerabilities( + target, + vulnerabilities, + pretty, + entitledForJas, + applicabilityRuns, + addSarifScaVulnerability(&sarifResults, &rules), + ) + return sarifResults, rules, err +} + +func addSarifScaVulnerability(sarifResults *[]*sarif.Result, rules *map[string]*sarif.ReportingDescriptor) results.PrepareScaVulnerabilityFunc { + return func(vulnerability services.Vulnerability, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersions []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { + maxCveScore, err := results.FindMaxCVEScore(severity, applicabilityStatus, cves) + if err != nil { + return err + } + markdownDescription, err := getScaIssueMarkdownDescription(directComponents, maxCveScore, applicabilityStatus, fixedVersions) + if err != nil { + return err + } + currentResults, currentRule, err := parseScaToSarifFormat(vulnerability.IssueId, vulnerability.Summary, markdownDescription, maxCveScore, getScaIssueSarifHeadline, cves, severity, applicabilityStatus, impactedPackagesName, impactedPackagesVersion, fixedVersions, directComponents) + if err != nil { + return err + } + cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, results.GetIssueIdentifier(cves, vulnerability.IssueId, "_")) + if _, ok := (*rules)[cveImpactedComponentRuleId]; !ok { + // New Rule + (*rules)[cveImpactedComponentRuleId] = currentRule + } + *sarifResults = append(*sarifResults, currentResults...) + return nil + } +} + +func addSarifScaSecurityViolation(sarifResults *[]*sarif.Result, rules *map[string]*sarif.ReportingDescriptor) results.PrepareScaViolationFunc { + return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersions []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { + maxCveScore, err := results.FindMaxCVEScore(severity, applicabilityStatus, cves) + if err != nil { + return err + } + markdownDescription, err := getScaIssueMarkdownDescription(directComponents, maxCveScore, applicabilityStatus, fixedVersions) + if err != nil { + return err + } + currentResults, currentRule, err := parseScaToSarifFormat(violation.IssueId, violation.Summary, markdownDescription, maxCveScore, getScaIssueSarifHeadline, cves, severity, applicabilityStatus, impactedPackagesName, impactedPackagesVersion, fixedVersions, directComponents) + if err != nil { + return err + } + cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, results.GetIssueIdentifier(cves, violation.IssueId, "_")) + if _, ok := (*rules)[cveImpactedComponentRuleId]; !ok { + // New Rule + (*rules)[cveImpactedComponentRuleId] = currentRule + } + *sarifResults = append(*sarifResults, currentResults...) + return nil + } +} + +func addSarifScaLicenseViolation(sarifResults *[]*sarif.Result, rules *map[string]*sarif.ReportingDescriptor) results.PrepareScaViolationFunc { + return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersions []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { + maxCveScore, err := results.FindMaxCVEScore(severity, applicabilityStatus, cves) + if err != nil { + return err + } + markdownDescription, err := getScaLicenseViolationMarkdown(impactedPackagesName, impactedPackagesVersion, violation.LicenseKey, directComponents) + if err != nil { + return err + } + currentResults, currentRule, err := parseScaToSarifFormat( + violation.LicenseKey, + getLicenseViolationSummary(impactedPackagesName, impactedPackagesVersion, violation.LicenseKey), + markdownDescription, + maxCveScore, + getXrayLicenseSarifHeadline, + cves, + severity, + applicabilityStatus, + impactedPackagesName, + impactedPackagesVersion, + fixedVersions, + directComponents, + ) + if err != nil { + return err + } + cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, results.GetIssueIdentifier(cves, violation.LicenseKey, "_")) + if _, ok := (*rules)[cveImpactedComponentRuleId]; !ok { + // New Rule + (*rules)[cveImpactedComponentRuleId] = currentRule + } + *sarifResults = append(*sarifResults, currentResults...) + return nil + } +} + +func parseScaToSarifFormat(xrayId, summary, markdownDescription, cveScore string, generateTitleFunc func(depName string, version string, issueId string) string, cves []formats.CveRow, severity severityutils.Severity, applicabilityStatus jasutils.ApplicabilityStatus, impactedPackagesName, impactedPackagesVersion string, fixedVersions []string, directComponents []formats.ComponentRow) (sarifResults []*sarif.Result, rule *sarif.ReportingDescriptor, e error) { + issueId := results.GetIssueIdentifier(cves, xrayId, "_") + cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, issueId) + // Add rule if not exists + rule = getScaIssueSarifRule( + cveImpactedComponentRuleId, + generateTitleFunc(impactedPackagesName, impactedPackagesVersion, issueId), + cveScore, + summary, + markdownDescription, + ) + // Add result for each component + level := severityutils.SeverityToSarifSeverityLevel(severity) + for _, directDependency := range directComponents { + msg := generateTitleFunc(directDependency.Name, directDependency.Version, issueId) + issueLocation := getComponentSarifLocation(directDependency) + issueResult := sarif.NewRuleResult(cveImpactedComponentRuleId). + WithMessage(sarif.NewTextMessage(msg)). + WithLevel(level.String()) + if issueLocation != nil { + issueResult.AddLocation(issueLocation) + } + sarifResults = append(sarifResults, issueResult) + } + return +} + +func getScaIssueSarifRule(ruleId, ruleDescription, maxCveScore, summary, markdownDescription string) *sarif.ReportingDescriptor { + cveRuleProperties := sarif.NewPropertyBag() + cveRuleProperties.Add(severityutils.SarifSeverityRuleProperty, maxCveScore) + return sarif.NewRule(ruleId). + WithDescription(ruleDescription). + WithHelp(sarif.NewMultiformatMessageString(summary).WithMarkdown(markdownDescription)). + WithProperties(cveRuleProperties.Properties) +} + +func getComponentSarifLocation(component formats.ComponentRow) *sarif.Location { + filePath := "" + if component.Location != nil { + filePath = component.Location.File + } + if strings.TrimSpace(filePath) == "" { + // For tech that we don't support fetching the package descriptor related to the component + filePath = "Package-Descriptor" + } + // TODO: Add to location the following + // https://sarifweb.azurewebsites.net/Validation + // "logicalLocations": [ + // { + // "fullyQualifiedName": "pkg:maven/org.xerial.snappy/snappy-java@1.1.10.1" + // } + // ] + return sarif.NewLocation(). + WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://" + filePath))) +} + +func getScaIssueMarkdownDescription(directDependencies []formats.ComponentRow, cveScore string, applicableStatus jasutils.ApplicabilityStatus, fixedVersions []string) (string, error) { + formattedDirectDependencies, err := getDirectDependenciesFormatted(directDependencies) + if err != nil { + return "", err + } + descriptionFixVersions := "No fix available" + if len(fixedVersions) > 0 { + descriptionFixVersions = strings.Join(fixedVersions, ", ") + } + if applicableStatus == jasutils.NotScanned { + return fmt.Sprintf("| Severity Score | Direct Dependencies | Fixed Versions |\n| :---: | :----: | :---: |\n| %s | %s | %s |", + cveScore, formattedDirectDependencies, descriptionFixVersions), nil + } + return fmt.Sprintf("| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| %s | %s | %s | %s |", + cveScore, applicableStatus.String(), formattedDirectDependencies, descriptionFixVersions), nil +} + +func getDirectDependenciesFormatted(directDependencies []formats.ComponentRow) (string, error) { + var formattedDirectDependencies strings.Builder + for _, dependency := range directDependencies { + if _, err := formattedDirectDependencies.WriteString(fmt.Sprintf("`%s %s`
", dependency.Name, dependency.Version)); err != nil { + return "", err + } + } + return strings.TrimSuffix(formattedDirectDependencies.String(), "
"), nil +} + +func getScaIssueSarifHeadline(depName, version, issueId string) string { + return fmt.Sprintf("[%s] %s %s", issueId, depName, version) +} + +func getXrayLicenseSarifHeadline(depName, version, key string) string { + return fmt.Sprintf("License violation [%s] %s %s", key, depName, version) +} + +func getLicenseViolationSummary(depName, version, key string) string { + return fmt.Sprintf("Dependency %s version %s is using a license (%s) that is not allowed.", depName, version, key) +} + +func getScaLicenseViolationMarkdown(depName, version, key string, directDependencies []formats.ComponentRow) (string, error) { + formattedDirectDependencies, err := getDirectDependenciesFormatted(directDependencies) + if err != nil { + return "", err + } + return fmt.Sprintf("**The following direct dependencies are utilizing the `%s %s` dependency with `%s` license violation:**\n%s", depName, version, key, formattedDirectDependencies), nil +} \ No newline at end of file diff --git a/utils/results/conversion/sarifparser/sarifparser_test.go b/utils/results/conversion/sarifparser/sarifparser_test.go new file mode 100644 index 00000000..56c91810 --- /dev/null +++ b/utils/results/conversion/sarifparser/sarifparser_test.go @@ -0,0 +1,206 @@ +package sarifparser + +import ( + "fmt" + "path/filepath" + "testing" + + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/owenrumney/go-sarif/v2/sarif" + "github.com/stretchr/testify/assert" +) + +func TestGetComponentSarifLocation(t *testing.T) { + testCases := []struct { + name string + component formats.ComponentRow + expectedOutput *sarif.Location + }{ + { + name: "Component with name and version", + component: formats.ComponentRow{ + Name: "example-package", + Version: "1.0.0", + }, + expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation(). + WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://Package-Descriptor")), + ), + }, + { + name: "Component with location", + component: formats.ComponentRow{ + Name: "example-package", + Version: "1.0.0", + Location: &formats.Location{File: filepath.Join("dir", "file.txt")}, + }, + expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation(). + WithArtifactLocation(sarif.NewArtifactLocation().WithUri(fmt.Sprintf("file://%s", filepath.Join("dir", "file.txt")))), + ), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.expectedOutput, getComponentSarifLocation(tc.component)) + }) + } +} + +func TestGetVulnerabilityOrViolationSarifHeadline(t *testing.T) { + assert.Equal(t, "[CVE-2022-1234] loadsh 1.4.1", getScaIssueSarifHeadline("loadsh", "1.4.1", "CVE-2022-1234")) + assert.NotEqual(t, "[CVE-2022-1234] comp 1.4.1", getScaIssueSarifHeadline("comp", "1.2.1", "CVE-2022-1234")) +} + +func TestgetXrayLicenseSarifHeadline(t *testing.T) { + assert.Equal(t, "License violation [MIT] in loadsh 1.4.1", getXrayLicenseSarifHeadline("loadsh", "1.4.1", "MIT")) + assert.NotEqual(t, "License violation [] in comp 1.2.1", getXrayLicenseSarifHeadline("comp", "1.2.1", "MIT")) +} + +func TestGetLicenseViolationSummary(t *testing.T) { + assert.Equal(t, "Dependency loadsh version 1.4.1 is using a license (MIT) that is not allowed.", getLicenseViolationSummary("loadsh", "1.4.1", "MIT")) + assert.NotEqual(t, "Dependency comp version 1.2.1 is using a license () that is not allowed.", getLicenseViolationSummary("comp", "1.2.1", "MIT")) +} + +func TestGetSarifTableDescription(t *testing.T) { + testCases := []struct { + name string + directDependencies []formats.ComponentRow + cveScore string + applicableStatus jasutils.ApplicabilityStatus + fixedVersions []string + expectedDescription string + }{ + { + name: "Applicable vulnerability", + directDependencies: []formats.ComponentRow{ + {Name: "example-package", Version: "1.0.0"}, + }, + cveScore: "7.5", + applicableStatus: jasutils.Applicable, + fixedVersions: []string{"1.0.1", "1.0.2"}, + expectedDescription: "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.5 | Applicable | `example-package 1.0.0` | 1.0.1, 1.0.2 |", + }, + { + name: "Not-scanned vulnerability", + directDependencies: []formats.ComponentRow{ + {Name: "example-package", Version: "2.0.0"}, + }, + cveScore: "6.2", + applicableStatus: jasutils.NotScanned, + fixedVersions: []string{"2.0.1"}, + expectedDescription: "| Severity Score | Direct Dependencies | Fixed Versions |\n| :---: | :----: | :---: |\n| 6.2 | `example-package 2.0.0` | 2.0.1 |", + }, + { + name: "No fixed versions", + directDependencies: []formats.ComponentRow{ + {Name: "example-package", Version: "3.0.0"}, + }, + cveScore: "3.0", + applicableStatus: jasutils.NotScanned, + fixedVersions: []string{}, + expectedDescription: "| Severity Score | Direct Dependencies | Fixed Versions |\n| :---: | :----: | :---: |\n| 3.0 | `example-package 3.0.0` | No fix available |", + }, + { + name: "Not-covered vulnerability", + directDependencies: []formats.ComponentRow{ + {Name: "example-package", Version: "3.0.0"}, + }, + cveScore: "3.0", + applicableStatus: jasutils.NotCovered, + fixedVersions: []string{"3.0.1"}, + expectedDescription: "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.0 | Not covered | `example-package 3.0.0` | 3.0.1 |", + }, + { + name: "Undetermined vulnerability", + directDependencies: []formats.ComponentRow{ + {Name: "example-package", Version: "3.0.0"}, + }, + cveScore: "3.0", + applicableStatus: jasutils.ApplicabilityUndetermined, + fixedVersions: []string{"3.0.1"}, + expectedDescription: "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.0 | Undetermined | `example-package 3.0.0` | 3.0.1 |", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + output, err := getScaIssueMarkdownDescription(tc.directDependencies, tc.cveScore, tc.applicableStatus, tc.fixedVersions) + assert.NoError(t, err) + assert.Equal(t, tc.expectedDescription, output) + }) + } +} + +func TestGetDirectDependenciesFormatted(t *testing.T) { + testCases := []struct { + name string + directDeps []formats.ComponentRow + expectedOutput string + }{ + { + name: "Single direct dependency", + directDeps: []formats.ComponentRow{ + {Name: "example-package", Version: "1.0.0"}, + }, + expectedOutput: "`example-package 1.0.0`", + }, + { + name: "Multiple direct dependencies", + directDeps: []formats.ComponentRow{ + {Name: "dependency1", Version: "1.0.0"}, + {Name: "dependency2", Version: "2.0.0"}, + }, + expectedOutput: "`dependency1 1.0.0`
`dependency2 2.0.0`", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + output, err := getDirectDependenciesFormatted(tc.directDeps) + assert.NoError(t, err) + assert.Equal(t, tc.expectedOutput, output) + }) + } +} + +func TestGetScaLicenseViolationMarkdown(t *testing.T) { + testCases := []struct { + name string + license string + impactedDepName string + impactedDepVersion string + directDeps []formats.ComponentRow + expectedOutput string + }{ + { + name: "Single direct dependency", + license: "MIT", + impactedDepName: "example-package", + impactedDepVersion: "1.0.0", + directDeps: []formats.ComponentRow{ + {Name: "dependency1", Version: "1.0.0"}, + }, + expectedOutput: "Dependency example-package version 1.0.0 is using a license (MIT) that is not allowed.
Direct dependencies:
`dependency1 1.0.0`", + }, + { + name: "Multiple direct dependencies", + license: "MIT", + impactedDepName: "example-package", + impactedDepVersion: "1.0.0", + directDeps: []formats.ComponentRow{ + {Name: "dependency1", Version: "1.0.0"}, + {Name: "dependency2", Version: "2.0.0"}, + }, + expectedOutput: "Dependency example-package version 1.0.0 is using a license (MIT) that is not allowed.
Direct dependencies:
`dependency1 1.0.0`
`dependency2 2.0.0`", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + output, err := getScaLicenseViolationMarkdown(tc.impactedDepName, tc.impactedDepVersion, tc.license, tc.directDeps) + assert.NoError(t, err) + assert.Equal(t, tc.expectedOutput, output) + }) + } +} \ No newline at end of file diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go index 683a3a0a..626b8b0d 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go @@ -1 +1,448 @@ -package simplejsonparser \ No newline at end of file +package simplejsonparser + +import ( + "sort" + "strconv" + + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/severityutils" + "github.com/jfrog/jfrog-cli-security/utils/techutils" + "github.com/jfrog/jfrog-client-go/xray/services" + "github.com/owenrumney/go-sarif/v2/sarif" +) + +type CmdResultsSimpleJsonConverter struct { + // If supported, pretty print the output text + pretty bool + // Current stream parse cache information + current *formats.SimpleJsonResults + // General information on the current command results + entitledForJas bool +} + +func NewCmdResultsSimpleJsonConverter(pretty bool) *CmdResultsSimpleJsonConverter { + return &CmdResultsSimpleJsonConverter{pretty: pretty} +} + +func (sjc *CmdResultsSimpleJsonConverter) Get() *formats.SimpleJsonResults { + if sjc.current == nil { + return nil + } + sortResults(sjc.current) + return sjc.current +} + +func (sjc *CmdResultsSimpleJsonConverter) Reset(multiScanId, _ string, entitledForJas bool) (err error) { + sjc.current = &formats.SimpleJsonResults{MultiScanId: multiScanId} + sjc.entitledForJas = entitledForJas + return +} + +func (sjc *CmdResultsSimpleJsonConverter) ParseNewScanResultsMetadata(target string, errors error) (err error) { + if sjc.current == nil { + return results.ConvertorResetErr + } + if errors != nil { + sjc.current.Errors = append(sjc.current.Errors, formats.SimpleJsonError{FilePath: target, ErrorMessage: errors.Error()}) + } + return +} + +func (sjc *CmdResultsSimpleJsonConverter) ParseViolations(target string, _ techutils.Technology, violations []services.Violation, applicabilityRuns ...*sarif.Run) (err error) { + if sjc.current == nil { + return results.ConvertorResetErr + } + secViolationsSimpleJson, licViolationsSimpleJson, opRiskViolationsSimpleJson, err := PrepareSimpleJsonViolations(target, violations, sjc.entitledForJas, sjc.pretty, applicabilityRuns...) + if err != nil { + return + } + sjc.current.SecurityViolations = append(sjc.current.SecurityViolations, secViolationsSimpleJson...) + sjc.current.LicensesViolations = append(sjc.current.LicensesViolations, licViolationsSimpleJson...) + sjc.current.OperationalRiskViolations = append(sjc.current.OperationalRiskViolations, opRiskViolationsSimpleJson...) + return +} + +func (sjc *CmdResultsSimpleJsonConverter) ParseVulnerabilities(target string, _ techutils.Technology, vulnerabilities []services.Vulnerability, applicabilityRuns ...*sarif.Run) (err error) { + if sjc.current == nil { + return results.ConvertorResetErr + } + vulSimpleJson, err := PrepareSimpleJsonVulnerabilities(target, vulnerabilities, sjc.entitledForJas, sjc.pretty, applicabilityRuns...) + if err != nil || len(vulSimpleJson) == 0 { + return + } + sjc.current.Vulnerabilities = append(sjc.current.Vulnerabilities, vulSimpleJson...) + return +} + +func (sjc *CmdResultsSimpleJsonConverter) ParseLicenses(target string, _ techutils.Technology, licenses []services.License) (err error) { + if sjc.current == nil { + return results.ConvertorResetErr + } + licSimpleJson, err := PrepareSimpleJsonLicenses(target, licenses) + if err != nil || len(licSimpleJson) == 0 { + return + } + sjc.current.Licenses = append(sjc.current.Licenses, licSimpleJson...) + return +} + +func (sjc *CmdResultsSimpleJsonConverter) ParseSecrets(target string, secrets ...*sarif.Run) (err error) { + if !sjc.entitledForJas { + return + } + if sjc.current == nil { + return results.ConvertorResetErr + } + secretsSimpleJson, err := PrepareSimpleJsonJasIssues(target, sjc.entitledForJas, sjc.pretty, secrets...) + if err != nil || len(secretsSimpleJson) == 0 { + return + } + sjc.current.Secrets = append(sjc.current.Secrets, secretsSimpleJson...) + return +} + +func (sjc *CmdResultsSimpleJsonConverter) ParseIacs(target string, iacs ...*sarif.Run) (err error) { + if !sjc.entitledForJas { + return + } + if sjc.current == nil { + return results.ConvertorResetErr + } + iacSimpleJson, err := PrepareSimpleJsonJasIssues(target, sjc.entitledForJas, sjc.pretty, iacs...) + if err != nil || len(iacSimpleJson) == 0 { + return + } + sjc.current.Iacs = append(sjc.current.Iacs, iacSimpleJson...) + return +} + +func (sjc *CmdResultsSimpleJsonConverter) ParseSast(target string, sast ...*sarif.Run) (err error) { + if !sjc.entitledForJas { + return + } + if sjc.current == nil { + return results.ConvertorResetErr + } + sastSimpleJson, err := PrepareSimpleJsonJasIssues(target, sjc.entitledForJas, sjc.pretty, sast...) + if err != nil || len(sastSimpleJson) == 0 { + return + } + sjc.current.Sast = append(sjc.current.Sast, sastSimpleJson...) + return +} + +func PrepareSimpleJsonViolations(target string, violations []services.Violation, jasEntitled, pretty bool, applicabilityRuns ...*sarif.Run) ([]formats.VulnerabilityOrViolationRow, []formats.LicenseRow, []formats.OperationalRiskViolationRow, error) { + var securityViolationsRows []formats.VulnerabilityOrViolationRow + var licenseViolationsRows []formats.LicenseRow + var operationalRiskViolationsRows []formats.OperationalRiskViolationRow + err := results.PrepareScaViolations( + target, + violations, + jasEntitled, + pretty, + applicabilityRuns, + addSimpleJsonSecurityViolation(&securityViolationsRows, pretty), + addSimpleJsonLicenseViolation(&licenseViolationsRows, pretty), + addSimpleJsonOperationalRiskViolation(&operationalRiskViolationsRows, pretty), + ) + return securityViolationsRows, licenseViolationsRows, operationalRiskViolationsRows, err +} + +func PrepareSimpleJsonVulnerabilities(target string, vulnerabilities []services.Vulnerability, entitledForJas, pretty bool, applicabilityRuns ...*sarif.Run) ([]formats.VulnerabilityOrViolationRow, error) { + var vulnerabilitiesRows []formats.VulnerabilityOrViolationRow + err := results.PrepareScaVulnerabilities( + target, + vulnerabilities, + entitledForJas, + pretty, + applicabilityRuns, + addSimpleJsonVulnerability(&vulnerabilitiesRows, pretty), + ) + return vulnerabilitiesRows, err +} + +func addSimpleJsonVulnerability(vulnerabilitiesRows *[]formats.VulnerabilityOrViolationRow, pretty bool) results.PrepareScaVulnerabilityFunc { + return func(vulnerability services.Vulnerability, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { + *vulnerabilitiesRows = append(*vulnerabilitiesRows, + formats.VulnerabilityOrViolationRow{ + Summary: vulnerability.Summary, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: severityutils.GetAsDetails(severity, applicabilityStatus, pretty), + ImpactedDependencyName: impactedPackagesName, + ImpactedDependencyVersion: impactedPackagesVersion, + ImpactedDependencyType: impactedPackagesType, + Components: directComponents, + }, + FixedVersions: fixedVersion, + Cves: cves, + IssueId: vulnerability.IssueId, + References: vulnerability.References, + JfrogResearchInformation: convertJfrogResearchInformation(vulnerability.ExtendedInformation), + ImpactPaths: impactPaths, + Technology: techutils.Technology(vulnerability.Technology), + Applicable: applicabilityStatus.ToString(pretty), + }, + ) + return nil + } +} + +func addSimpleJsonSecurityViolation(securityViolationsRows *[]formats.VulnerabilityOrViolationRow, pretty bool) results.PrepareScaViolationFunc { + return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { + *securityViolationsRows = append(*securityViolationsRows, + formats.VulnerabilityOrViolationRow{ + Summary: violation.Summary, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: severityutils.GetAsDetails(severity, applicabilityStatus, pretty), + ImpactedDependencyName: impactedPackagesName, + ImpactedDependencyVersion: impactedPackagesVersion, + ImpactedDependencyType: impactedPackagesType, + Components: directComponents, + }, + FixedVersions: fixedVersion, + Cves: cves, + IssueId: violation.IssueId, + References: violation.References, + JfrogResearchInformation: convertJfrogResearchInformation(violation.ExtendedInformation), + ImpactPaths: impactPaths, + Technology: techutils.Technology(violation.Technology), + Applicable: applicabilityStatus.ToString(pretty), + }, + ) + return nil + } +} + +func addSimpleJsonLicenseViolation(licenseViolationsRows *[]formats.LicenseRow, pretty bool) results.PrepareScaViolationFunc { + return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { + *licenseViolationsRows = append(*licenseViolationsRows, + formats.LicenseRow{ + LicenseKey: violation.LicenseKey, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: severityutils.GetAsDetails(severity, applicabilityStatus, pretty), + ImpactedDependencyName: impactedPackagesName, + ImpactedDependencyVersion: impactedPackagesVersion, + ImpactedDependencyType: impactedPackagesType, + Components: directComponents, + }, + }, + ) + return nil + } +} + +func addSimpleJsonOperationalRiskViolation(operationalRiskViolationsRows *[]formats.OperationalRiskViolationRow, pretty bool) results.PrepareScaViolationFunc { + return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { + violationOpRiskData := getOperationalRiskViolationReadableData(violation) + for compIndex := 0; compIndex < len(impactedPackagesName); compIndex++ { + operationalRiskViolationsRow := &formats.OperationalRiskViolationRow{ + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: severityutils.GetAsDetails(severity, applicabilityStatus, pretty), + ImpactedDependencyName: impactedPackagesName, + ImpactedDependencyVersion: impactedPackagesVersion, + ImpactedDependencyType: impactedPackagesType, + Components: directComponents, + }, + IsEol: violationOpRiskData.isEol, + Cadence: violationOpRiskData.cadence, + Commits: violationOpRiskData.commits, + Committers: violationOpRiskData.committers, + NewerVersions: violationOpRiskData.newerVersions, + LatestVersion: violationOpRiskData.latestVersion, + RiskReason: violationOpRiskData.riskReason, + EolMessage: violationOpRiskData.eolMessage, + } + *operationalRiskViolationsRows = append(*operationalRiskViolationsRows, *operationalRiskViolationsRow) + } + return nil + } +} + +func PrepareSimpleJsonLicenses(target string, licenses []services.License) ([]formats.LicenseRow, error) { + var licensesRows []formats.LicenseRow + err := results.PrepareLicenses(target, licenses, addSimpleJsonLicense(&licensesRows)) + return licensesRows, err +} + +func addSimpleJsonLicense(licenseViolationsRows *[]formats.LicenseRow) results.PrepareLicensesFunc { + return func(license services.License, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { + *licenseViolationsRows = append(*licenseViolationsRows, + formats.LicenseRow{ + LicenseKey: license.Key, + ImpactPaths: impactPaths, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + ImpactedDependencyName: impactedPackagesName, + ImpactedDependencyVersion: impactedPackagesVersion, + ImpactedDependencyType: impactedPackagesType, + Components: directComponents, + }, + }, + ) + return nil + } +} + +func PrepareSimpleJsonJasIssues(target string, entitledForJas, pretty bool, jasIssues ...*sarif.Run) ([]formats.SourceCodeRow, error) { + var rows []formats.SourceCodeRow + err := results.PrepareJasIssues(target, jasIssues, entitledForJas, func(run *sarif.Run, rule *sarif.ReportingDescriptor, severity severityutils.Severity, result *sarif.Result, location *sarif.Location) error { + scannerDescription := "" + if rule != nil { + scannerDescription = sarifutils.GetRuleFullDescription(rule) + } + rows = append(rows, + formats.SourceCodeRow{ + SeverityDetails: severityutils.GetAsDetails(severity, jasutils.Applicable, pretty), + Finding: sarifutils.GetResultMsgText(result), + ScannerDescription: scannerDescription, + Location: formats.Location{ + File: sarifutils.GetRelativeLocationFileName(location, run.Invocations), + StartLine: sarifutils.GetLocationStartLine(location), + StartColumn: sarifutils.GetLocationStartColumn(location), + EndLine: sarifutils.GetLocationEndLine(location), + EndColumn: sarifutils.GetLocationEndColumn(location), + Snippet: sarifutils.GetLocationSnippet(location), + }, + CodeFlow: codeFlowToLocationFlow(sarifutils.GetLocationRelatedCodeFlowsFromResult(location, result), run.Invocations, pretty), + }, + ) + return nil + }) + return rows, err +} + +func codeFlowToLocationFlow(flows []*sarif.CodeFlow, invocations []*sarif.Invocation, isTable bool) (flowRows [][]formats.Location) { + if isTable { + // Not displaying in table + return + } + for _, codeFlow := range flows { + for _, stackTrace := range codeFlow.ThreadFlows { + rowFlow := []formats.Location{} + for _, stackTraceEntry := range stackTrace.Locations { + rowFlow = append(rowFlow, formats.Location{ + File: sarifutils.GetRelativeLocationFileName(stackTraceEntry.Location, invocations), + StartLine: sarifutils.GetLocationStartLine(stackTraceEntry.Location), + StartColumn: sarifutils.GetLocationStartColumn(stackTraceEntry.Location), + EndLine: sarifutils.GetLocationEndLine(stackTraceEntry.Location), + EndColumn: sarifutils.GetLocationEndColumn(stackTraceEntry.Location), + Snippet: sarifutils.GetLocationSnippet(stackTraceEntry.Location), + }) + } + flowRows = append(flowRows, rowFlow) + } + } + return +} + +func sortResults(simpleJsonResults *formats.SimpleJsonResults) { + if simpleJsonResults == nil { + return + } + if len(simpleJsonResults.SecurityViolations) > 0 { + sortVulnerabilityOrViolationRows(simpleJsonResults.SecurityViolations) + } + if len(simpleJsonResults.Vulnerabilities) > 0 { + sortVulnerabilityOrViolationRows(simpleJsonResults.Vulnerabilities) + } + if len(simpleJsonResults.LicensesViolations) > 0 { + sort.Slice(simpleJsonResults.LicensesViolations, func(i, j int) bool { + return simpleJsonResults.LicensesViolations[i].SeverityNumValue > simpleJsonResults.LicensesViolations[j].SeverityNumValue + }) + } + if len(simpleJsonResults.OperationalRiskViolations) > 0 { + sort.Slice(simpleJsonResults.OperationalRiskViolations, func(i, j int) bool { + return simpleJsonResults.OperationalRiskViolations[i].SeverityNumValue > simpleJsonResults.OperationalRiskViolations[j].SeverityNumValue + }) + } + if len(simpleJsonResults.Secrets) > 0 { + sort.Slice(simpleJsonResults.Secrets, func(i, j int) bool { + return simpleJsonResults.Secrets[i].SeverityNumValue > simpleJsonResults.Secrets[j].SeverityNumValue + }) + } + if len(simpleJsonResults.Iacs) > 0 { + sort.Slice(simpleJsonResults.Iacs, func(i, j int) bool { + return simpleJsonResults.Iacs[i].SeverityNumValue > simpleJsonResults.Iacs[j].SeverityNumValue + }) + } + if len(simpleJsonResults.Sast) > 0 { + sort.Slice(simpleJsonResults.Sast, func(i, j int) bool { + return simpleJsonResults.Sast[i].SeverityNumValue > simpleJsonResults.Sast[j].SeverityNumValue + }) + } +} + +func sortVulnerabilityOrViolationRows(rows []formats.VulnerabilityOrViolationRow) { + sort.Slice(rows, func(i, j int) bool { + if rows[i].SeverityNumValue != rows[j].SeverityNumValue { + return rows[i].SeverityNumValue > rows[j].SeverityNumValue + } + return len(rows[i].FixedVersions) > 0 && len(rows[j].FixedVersions) > 0 + }) +} + +func convertJfrogResearchInformation(extendedInfo *services.ExtendedInformation) *formats.JfrogResearchInformation { + if extendedInfo == nil { + return nil + } + var severityReasons []formats.JfrogResearchSeverityReason + for _, severityReason := range extendedInfo.JfrogResearchSeverityReasons { + severityReasons = append(severityReasons, formats.JfrogResearchSeverityReason{ + Name: severityReason.Name, + Description: severityReason.Description, + IsPositive: severityReason.IsPositive, + }) + } + return &formats.JfrogResearchInformation{ + Summary: extendedInfo.ShortDescription, + Details: extendedInfo.FullDescription, + SeverityDetails: formats.SeverityDetails{Severity: extendedInfo.JfrogResearchSeverity}, + SeverityReasons: severityReasons, + Remediation: extendedInfo.Remediation, + } +} + +type operationalRiskViolationReadableData struct { + isEol string + cadence string + commits string + committers string + eolMessage string + riskReason string + latestVersion string + newerVersions string +} + +func getOperationalRiskViolationReadableData(violation services.Violation) *operationalRiskViolationReadableData { + isEol, cadence, commits, committers, newerVersions, latestVersion := "N/A", "N/A", "N/A", "N/A", "N/A", "N/A" + if violation.IsEol != nil { + isEol = strconv.FormatBool(*violation.IsEol) + } + if violation.Cadence != nil { + cadence = strconv.FormatFloat(*violation.Cadence, 'f', -1, 64) + } + if violation.Committers != nil { + committers = strconv.FormatInt(int64(*violation.Committers), 10) + } + if violation.Commits != nil { + commits = strconv.FormatInt(*violation.Commits, 10) + } + if violation.NewerVersions != nil { + newerVersions = strconv.FormatInt(int64(*violation.NewerVersions), 10) + } + if violation.LatestVersion != "" { + latestVersion = violation.LatestVersion + } + return &operationalRiskViolationReadableData{ + isEol: isEol, + cadence: cadence, + commits: commits, + committers: committers, + eolMessage: violation.EolMessage, + riskReason: violation.RiskReason, + latestVersion: latestVersion, + newerVersions: newerVersions, + } +} \ No newline at end of file diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go new file mode 100644 index 00000000..fe262f78 --- /dev/null +++ b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go @@ -0,0 +1,505 @@ +package simplejsonparser + +import ( + "testing" + + "github.com/owenrumney/go-sarif/v2/sarif" + "github.com/stretchr/testify/assert" + + "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-client-go/xray/services" +) + +func TestSortVulnerabilityOrViolationRows(t *testing.T) { + testCases := []struct { + name string + rows []formats.VulnerabilityOrViolationRow + expectedOrder []string + }{ + { + name: "Sort by severity with different severity values", + rows: []formats.VulnerabilityOrViolationRow{ + { + Summary: "Summary 1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{ + Severity: "High", + SeverityNumValue: 9, + }, + ImpactedDependencyName: "Dependency 1", + ImpactedDependencyVersion: "1.0.0", + }, + FixedVersions: []string{}, + }, + { + Summary: "Summary 2", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{ + Severity: "Critical", + SeverityNumValue: 12, + }, + ImpactedDependencyName: "Dependency 2", + ImpactedDependencyVersion: "2.0.0", + }, + FixedVersions: []string{"1.0.0"}, + }, + { + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{ + Severity: "Medium", + SeverityNumValue: 6, + }, + ImpactedDependencyName: "Dependency 3", + ImpactedDependencyVersion: "3.0.0", + }, + Summary: "Summary 3", + FixedVersions: []string{}, + }, + }, + expectedOrder: []string{"Dependency 2", "Dependency 1", "Dependency 3"}, + }, + { + name: "Sort by severity with same severity values, but different fixed versions", + rows: []formats.VulnerabilityOrViolationRow{ + { + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{ + Severity: "Critical", + SeverityNumValue: 12, + }, + ImpactedDependencyName: "Dependency 1", + ImpactedDependencyVersion: "1.0.0", + }, + Summary: "Summary 1", + FixedVersions: []string{"1.0.0"}, + }, + { + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{ + Severity: "Critical", + SeverityNumValue: 12, + }, + ImpactedDependencyName: "Dependency 2", + ImpactedDependencyVersion: "2.0.0", + }, + Summary: "Summary 2", + FixedVersions: []string{}, + }, + }, + expectedOrder: []string{"Dependency 1", "Dependency 2"}, + }, + { + name: "Sort by severity with same severity values different applicability", + rows: []formats.VulnerabilityOrViolationRow{ + { + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{ + Severity: "Critical", + SeverityNumValue: 13, + }, + ImpactedDependencyName: "Dependency 1", + ImpactedDependencyVersion: "1.0.0", + }, + Summary: "Summary 1", + Applicable: jasutils.Applicable.String(), + FixedVersions: []string{"1.0.0"}, + }, + { + Summary: "Summary 2", + Applicable: jasutils.NotApplicable.String(), + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{ + Severity: "Critical", + SeverityNumValue: 11, + }, + ImpactedDependencyName: "Dependency 2", + ImpactedDependencyVersion: "2.0.0", + }, + }, + { + Summary: "Summary 3", + Applicable: jasutils.ApplicabilityUndetermined.String(), + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{ + Severity: "Critical", + SeverityNumValue: 12, + }, + ImpactedDependencyName: "Dependency 3", + ImpactedDependencyVersion: "2.0.0", + }, + }, + }, + expectedOrder: []string{"Dependency 1", "Dependency 3", "Dependency 2"}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + sortVulnerabilityOrViolationRows(tc.rows) + + for i, row := range tc.rows { + assert.Equal(t, tc.expectedOrder[i], row.ImpactedDependencyName) + } + }) + } +} + +func TestGetOperationalRiskReadableData(t *testing.T) { + tests := []struct { + violation services.Violation + expectedResults *operationalRiskViolationReadableData + }{ + { + services.Violation{IsEol: nil, LatestVersion: "", NewerVersions: nil, + Cadence: nil, Commits: nil, Committers: nil, RiskReason: "", EolMessage: ""}, + &operationalRiskViolationReadableData{"N/A", "N/A", "N/A", "N/A", "", "", "N/A", "N/A"}, + }, + { + services.Violation{IsEol: utils.NewBoolPtr(true), LatestVersion: "1.2.3", NewerVersions: utils.NewIntPtr(5), + Cadence: utils.NewFloat64Ptr(3.5), Commits: utils.NewInt64Ptr(55), Committers: utils.NewIntPtr(10), EolMessage: "no maintainers", RiskReason: "EOL"}, + &operationalRiskViolationReadableData{"true", "3.5", "55", "10", "no maintainers", "EOL", "1.2.3", "5"}, + }, + } + + for _, test := range tests { + results := getOperationalRiskViolationReadableData(test.violation) + assert.Equal(t, test.expectedResults, results) + } +} + +func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { + testScaScanResults := []services.Vulnerability{ + { + IssueId: "XRAY-1", + Summary: "summary-1", + Severity: "High", + Cves: []services.Cve{{Id: "CVE-1"}}, + Components: map[string]services.Component{"component-A": {}, "component-B": {}}, + }, + { + IssueId: "XRAY-2", + Summary: "summary-2", + Severity: "Low", + Cves: []services.Cve{{Id: "CVE-2"}}, + Components: map[string]services.Component{"component-B": {}}, + }, + } + + testCases := []struct { + name string + input []services.Vulnerability + target string + entitledForJas bool + pretty bool + applicablityRuns []*sarif.Run + expectedOutput []formats.VulnerabilityOrViolationRow + }{ + { + name: "No vulnerabilities", + input: []services.Vulnerability{}, + target: "target", + entitledForJas: false, + pretty: false, + applicablityRuns: []*sarif.Run{}, + expectedOutput: []formats.VulnerabilityOrViolationRow{}, + }, + { + name: "Vulnerabilities with no applicability", + input: testScaScanResults, + target: "target", + entitledForJas: false, + pretty: false, + applicablityRuns: []*sarif.Run{}, + expectedOutput: []formats.VulnerabilityOrViolationRow{ + { + Summary: "summary-1", + IssueId: "XRAY-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "component-A", + }, + }, + { + Summary: "summary-1", + IssueId: "XRAY-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "component-B", + }, + }, + { + Summary: "summary-2", + IssueId: "XRAY-2", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "Low"}, + ImpactedDependencyName: "component-B", + }, + }, + }, + }, + { + name: "Vulnerabilities with applicability", + input: testScaScanResults, + target: "target", + entitledForJas: true, + pretty: false, + applicablityRuns: []*sarif.Run{ + sarifutils.CreateRunWithDummyResults( + sarifutils.CreateDummyPassingResult("applic_CVE-1"), + sarifutils.CreateResultWithLocations("applic_CVE-2", "applic_CVE-2", "note", sarifutils.CreateLocation("target/file", 0, 0, 0, 0, "snippet")), + ).WithInvocations([]*sarif.Invocation{ + sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target")), + }), + }, + expectedOutput: []formats.VulnerabilityOrViolationRow{ + { + Summary: "summary-1", + IssueId: "XRAY-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "component-A", + Components: []formats.ComponentRow{{Name: "component-A", Location: &formats.Location{File: "target"}}}, + }, + Applicable: jasutils.NotApplicable.String(), + Cves: []formats.CveRow{{Id: "CVE-1"}}, + }, + { + Summary: "summary-1", + IssueId: "XRAY-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "component-B", + Components: []formats.ComponentRow{{Name: "component-B", Location: &formats.Location{File: "target"}}}, + }, + Applicable: jasutils.NotApplicable.String(), + Cves: []formats.CveRow{{Id: "CVE-1"}}, + }, + { + Summary: "summary-2", + IssueId: "XRAY-2", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "Low"}, + ImpactedDependencyName: "component-B", + Components: []formats.ComponentRow{{Name: "component-B", Location: &formats.Location{File: "target"}}}, + }, + Applicable: jasutils.Applicability.String(), + Cves: []formats.CveRow{{ + Id: "CVE-2", + Applicability: &formats.Applicability{ + Status: jasutils.Applicability.String(), + Evidence: []formats.Evidence{formats.Evidence{ + Location: formats.Location{File: "target/file", StartLine: 0, StartColumn: 0, EndLine: 0, EndColumn: 0, Snippet: "snippet"}, + }}, + }, + }}, + }, + }, + }, + { + name: "Vulnerabilities only - with allowed licenses", + input: testScaScanResults, + target: "target", + entitledForJas: false, + pretty: false, + applicablityRuns: []*sarif.Run{}, + expectedOutput: []formats.VulnerabilityOrViolationRow{ + { + Summary: "summary-1", + IssueId: "XRAY-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "high"}, + ImpactedDependencyName: "component-A", + }, + }, + { + Summary: "summary-1", + IssueId: "XRAY-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "high"}, + ImpactedDependencyName: "component-B", + }, + }, + { + Summary: "summary-2", + IssueId: "XRAY-2", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "low"}, + ImpactedDependencyName: "component-B", + }, + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + out, err := PrepareSimpleJsonVulnerabilities(tc.target, tc.input, tc.entitledForJas, tc.pretty, tc.applicablityRuns...) + assert.NoError(t, err) + assert.ElementsMatch(t, tc.expectedOutput, out) + }) + } +} + +func TestPrepareSimpleJsonViolations(t *testing.T) { + testCases := []struct { + name string + input []services.Violation + target string + entitledForJas bool + pretty bool + applicablityRuns []*sarif.Run + expectedSecurityOutput []formats.VulnerabilityOrViolationRow + expectedLicenseOutput []formats.LicenseRow + expectedOperationalRiskOutput []formats.OperationalRiskViolationRow + }{ + { + name: "No violations", + input: []services.Violation{}, + target: "target", + entitledForJas: false, + pretty: false, + applicablityRuns: []*sarif.Run{}, + expectedSecurityOutput: []formats.VulnerabilityOrViolationRow{}, + }, + { + name: "Violations with no applicability", + input: []services.Violation{ + { + IssueId: "XRAY-1", + Summary: "summary-1", + Severity: "High", + ViolationType: "security", + Components: map[string]services.Component{"component-A": {}, "component-B": {}}, + }, + { + IssueId: "XRAY-2", + Summary: "summary-2", + Severity: "Low", + ViolationType: "license", + LicenseKey: "license-1", + Components: map[string]services.Component{"component-B": {}}, + }, + }, + target: "target", + entitledForJas: false, + pretty: false, + applicablityRuns: []*sarif.Run{}, + expectedSecurityOutput: []formats.VulnerabilityOrViolationRow{ + { + Summary: "summary-1", + IssueId: "XRAY-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "component-A", + }, + }, + { + Summary: "summary-1", + IssueId: "XRAY-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "component-B", + }, + }, + { + Summary: "summary-2", + IssueId: "XRAY-2", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "Low"}, + ImpactedDependencyName: "component-B", + }, + }, + }, + }, + { + name: "Violations with applicability", + input: []services.Violation{ + { + IssueId: "XRAY-1", + Summary: "summary-1", + Severity: "High", + WatchName: "watch-1", + ViolationType: "security", + Components: map[string]services.Component{"component-A": {}, "component-B": {}}, + }, + { + IssueId: "XRAY-2", + Summary: "summary-2", + Severity: "Low", + WatchName: "watch-1", + ViolationType: "license", + LicenseKey: "license-1", + Components: map[string]services.Component{"component-B": {}}, + }, + }, + target: "target", + entitledForJas: true, + pretty: false, + applicablityRuns: []*sarif.Run{ + sarifutils.CreateRunWithDummyResults( + sarifutils.CreateDummyPassingResult("applic_CVE-1"), + sarifutils.CreateResultWithLocations("applic_CVE-2", "applic_CVE-2", "note", sarifutils.CreateLocation("target/file", 0, 0, 0, 0, "snippet")), + ).WithInvocations([]*sarif.Invocation{ + sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target")), + }), + }, + expectedSecurityOutput: []formats.VulnerabilityOrViolationRow{ + { + Summary: "summary-1", + IssueId: "XRAY-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "component-A", + Components: []formats.ComponentRow{{Name: "component-A", Location: &formats.Location{File: "target"}}}, + }, + Applicable: jasutils.NotApplicable.String(), + }, + { + Summary: "summary-1", + IssueId: "XRAY-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "component-B", + Components: []formats.ComponentRow{{Name: "component-B", Location: &formats.Location{File: "target"}}}, + }, + Applicable: jasutils.NotApplicable.String(), + }, + { + Summary: "summary-2", + IssueId: "XRAY-2", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "Low"}, + ImpactedDependencyName: "component-B", + Components: []formats.ComponentRow{{Name: "component-B", Location: &formats.Location{File: "target"}}}, + }, + Applicable: jasutils.Applicability.String(), + }, + }, + }, + { + name: "Violations - override allowed licenses", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + securityOutput, licenseOutput, operationalRiskOutput, err := PrepareSimpleJsonViolations(tc.target, tc.input, tc.entitledForJas, tc.pretty, tc.applicablityRuns...) + assert.NoError(t, err) + assert.ElementsMatch(t, tc.expectedSecurityOutput, securityOutput) + assert.ElementsMatch(t, tc.expectedLicenseOutput, licenseOutput) + assert.ElementsMatch(t, tc.expectedOperationalRiskOutput, operationalRiskOutput) + }) + } + +} + +func TestPrepareSimpleJsonLicenses(t *testing.T) { + +} + +func TestPrepareSimpleJsonJasIssues(t *testing.T) { + +} \ No newline at end of file diff --git a/utils/results/conversion/summaryparser/summaryparser.go b/utils/results/conversion/summaryparser/summaryparser.go index 2a21aa42..02083f62 100644 --- a/utils/results/conversion/summaryparser/summaryparser.go +++ b/utils/results/conversion/summaryparser/summaryparser.go @@ -1 +1,214 @@ -package summaryparser \ No newline at end of file +package summaryparser + +import ( + "github.com/jfrog/gofrog/datastructures" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/severityutils" + "github.com/jfrog/jfrog-cli-security/utils/techutils" + "github.com/jfrog/jfrog-client-go/xray/services" + "github.com/owenrumney/go-sarif/v2/sarif" +) + +type CmdResultsSummaryConverter struct { + current *formats.SummaryResults + currentScan *formats.ScanSummaryResult + currentCveUnique *datastructures.Set[string] + entitledForJas bool +} + +func NewCmdResultsSummaryConverter() *CmdResultsSummaryConverter { + return &CmdResultsSummaryConverter{} +} + +func (sc *CmdResultsSummaryConverter) Get() *formats.SummaryResults { + if sc.current == nil { + return &formats.SummaryResults{} + } + // Flush the last scan + sc.ParseNewScanResultsMetadata("", nil) + return sc.current +} + +func (sc *CmdResultsSummaryConverter) Reset(_, _ string, entitledForJas bool) (err error) { + sc.current = &formats.SummaryResults{} + sc.entitledForJas = entitledForJas + sc.currentCveUnique = datastructures.MakeSet[string]() + return +} + +func (sc *CmdResultsSummaryConverter) ParseNewScanResultsMetadata(target string, errors error) (err error) { + if sc.current == nil { + return results.ConvertorResetErr + } + if sc.currentScan != nil { + sc.current.Scans = append(sc.current.Scans, *sc.currentScan) + } + sc.currentScan = &formats.ScanSummaryResult{Target: target} + return +} + +func (sc *CmdResultsSummaryConverter) ParseViolations(target string, _ techutils.Technology, violations []services.Violation, applicabilityRuns ...*sarif.Run) (err error) { + if sc.current == nil { + return results.ConvertorResetErr + } + if sc.currentScan == nil { + return results.ConvertorNewScanErr + } + if sc.currentScan.Vulnerabilities == nil { + sc.currentScan.Vulnerabilities = &formats.ScanVulnerabilitiesSummary{} + } + if sc.currentScan.Vulnerabilities.ScaScanResults == nil { + sc.currentScan.Vulnerabilities.ScaScanResults = &formats.ScanScaResult{} + } + err = results.PrepareScaViolations( + target, + violations, + sc.entitledForJas, + false, + applicabilityRuns, + sc.getScaViolationHandler(), + sc.getScaViolationHandler(), + sc.getScaViolationHandler(), + ) + return +} + +func (sc *CmdResultsSummaryConverter) getScaViolationHandler() results.PrepareScaViolationFunc { + return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) (err error) { + for i := 0; i < len(getCveIds(cves, violation.IssueId)); i++ { + sc.currentScan.Violations[violation.ViolationType][severity.String()]++ + } + return + } +} + +func (sc *CmdResultsSummaryConverter) ParseVulnerabilities(target string, tech techutils.Technology, vulnerabilities []services.Vulnerability, applicabilityRuns ...*sarif.Run) (err error) { + if sc.current == nil { + return results.ConvertorResetErr + } + if sc.currentScan == nil { + return results.ConvertorNewScanErr + } + if sc.currentScan.Vulnerabilities == nil { + sc.currentScan.Vulnerabilities = &formats.ScanVulnerabilitiesSummary{} + } + if sc.currentScan.Vulnerabilities.ScaScanResults == nil { + sc.currentScan.Vulnerabilities.ScaScanResults = &formats.ScanScaResult{} + } + err = results.PrepareScaVulnerabilities( + target, + vulnerabilities, + sc.entitledForJas, + false, + applicabilityRuns, + func(vulnerability services.Vulnerability, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { + for _, id := range getCveIds(cves, vulnerability.IssueId) { + issueId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, id) + if !sc.currentCveUnique.Exists(issueId) { + sc.currentScan.Vulnerabilities.ScaScanResults.UniqueFindings++ + sc.currentCveUnique.Add(issueId) + } + sc.currentScan.Vulnerabilities.ScaScanResults.SummaryCount[severity.String()][applicabilityStatus.String()]++ + } + return nil + }, + ) + return +} + +func getCveIds(cves []formats.CveRow, issueId string) []string { + ids := []string{} + for _, cve := range cves { + ids = append(ids, cve.Id) + } + if len(ids) == 0 { + ids = append(ids, issueId) + } + return ids +} + +func (sc *CmdResultsSummaryConverter) ParseLicenses(target string, tech techutils.Technology, licenses []services.License) (err error) { + // Not supported in the summary + return +} + +func (sc *CmdResultsSummaryConverter) ParseSecrets(target string, secrets ...*sarif.Run) (err error) { + if !sc.entitledForJas { + return + } + if sc.current == nil { + return results.ConvertorResetErr + } + if sc.currentScan == nil { + return results.ConvertorNewScanErr + } + if sc.currentScan.Vulnerabilities == nil { + sc.currentScan.Vulnerabilities = &formats.ScanVulnerabilitiesSummary{} + } + if sc.currentScan.Vulnerabilities.SecretsScanResults == nil { + sc.currentScan.Vulnerabilities.SecretsScanResults = &formats.SummaryCount{} + } + return results.PrepareJasIssues(target, secrets, sc.entitledForJas, sc.getJasHandler(jasutils.Secrets)) +} + +func (sc *CmdResultsSummaryConverter) ParseIacs(target string, iacs ...*sarif.Run) (err error) { + if !sc.entitledForJas { + return + } + if sc.current == nil { + return results.ConvertorResetErr + } + if sc.currentScan == nil { + return results.ConvertorNewScanErr + } + if sc.currentScan.Vulnerabilities == nil { + sc.currentScan.Vulnerabilities = &formats.ScanVulnerabilitiesSummary{} + } + if sc.currentScan.Vulnerabilities.IacScanResults == nil { + sc.currentScan.Vulnerabilities.IacScanResults = &formats.SummaryCount{} + } + return results.PrepareJasIssues(target, iacs, sc.entitledForJas, sc.getJasHandler(jasutils.IaC)) +} + +func (sc *CmdResultsSummaryConverter) ParseSast(target string, sast ...*sarif.Run) (err error) { + if !sc.entitledForJas { + return + } + if sc.current == nil { + return results.ConvertorResetErr + } + if sc.currentScan == nil { + return results.ConvertorNewScanErr + } + if sc.currentScan.Vulnerabilities == nil { + sc.currentScan.Vulnerabilities = &formats.ScanVulnerabilitiesSummary{} + } + if sc.currentScan.Vulnerabilities.SastScanResults == nil { + sc.currentScan.Vulnerabilities.SastScanResults = &formats.SummaryCount{} + } + return results.PrepareJasIssues(target, sast, sc.entitledForJas, sc.getJasHandler(jasutils.Sast)) +} + +func (sc *CmdResultsSummaryConverter) getJasHandler(scanType jasutils.JasScanType) results.PrepareJasFunc { + return func(run *sarif.Run, rule *sarif.ReportingDescriptor, severity severityutils.Severity, result *sarif.Result, location *sarif.Location) (err error) { + if location == nil { + return + } + var count *formats.SummaryCount + switch scanType { + case jasutils.Secrets: + count = sc.currentScan.Vulnerabilities.SecretsScanResults + case jasutils.IaC: + count = sc.currentScan.Vulnerabilities.IacScanResults + case jasutils.Sast: + count = sc.currentScan.Vulnerabilities.SastScanResults + } + if count == nil { + return + } + (*count)[severity.String()]++ + return + } +} \ No newline at end of file diff --git a/utils/results/conversion/summaryparser/summaryparser_test.go b/utils/results/conversion/summaryparser/summaryparser_test.go new file mode 100644 index 00000000..d7f957f3 --- /dev/null +++ b/utils/results/conversion/summaryparser/summaryparser_test.go @@ -0,0 +1,166 @@ +package summaryparser + +import ( + "testing" + + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/stretchr/testify/assert" +) + +func TestGetCveIds(t *testing.T) { + testCases := []struct { + name string + cves []formats.CveRow + issueId string + expected []string + }{ + { + name: "No cves", + cves: []formats.CveRow{}, + issueId: "issueId", + expected: []string{"issueId"}, + }, + { + name: "One cve", + cves: []formats.CveRow{{Id: "CVE-1"}}, + issueId: "issueId", + expected: []string{"CVE-1"}, + }, + { + name: "Multiple cves", + cves: []formats.CveRow{{Id: "CVE-1"}, {Id: "CVE-2"}}, + issueId: "issueId", + expected: []string{"CVE-1", "CVE-2"}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result := getCveIds(testCase.cves, testCase.issueId) + assert.Equal(t, testCase.expected, result) + }) + } +} + +// func TestGetSummary(t *testing.T) { +// dummyExtendedScanResults := &ExtendedScanResults{ +// ApplicabilityScanResults: []*sarif.Run{ +// sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyPassingResult("applic_CVE-2")).WithInvocations([]*sarif.Invocation{ +// sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target1")), +// }), +// }, +// SecretsScanResults: []*sarif.Run{ +// sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("target1/file", 0, 0, 0, 0, "snippet"))).WithInvocations([]*sarif.Invocation{ +// sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target1")), +// }), +// sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("target2/file", 0, 0, 0, 0, "snippet"))).WithInvocations([]*sarif.Invocation{ +// sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target2")), +// }), +// }, +// SastScanResults: []*sarif.Run{ +// sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("target1/file2", 0, 0, 0, 0, "snippet"))).WithInvocations([]*sarif.Invocation{ +// sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target1")), +// }), +// }, +// } + +// testCases := []struct { +// name string +// cmdResults results.ScanCommandResults +// expected formats.SummaryResults +// findingCount int +// issueCount int +// }{ +// { +// name: "Empty results", +// cmdResults: results.ScanCommandResults{ScaResults: []ScaScanResult{}}, +// expected: formats.SummaryResults{Scans: []formats.ScanSummaryResult{{}}}, +// findingCount: 0, +// issueCount: 0, +// }, +// { +// name: "One module result", +// cmdResults: results.ScanCommandResults{ +// ScaResults: []ScaScanResult{{ +// Target: "target1", +// XrayResults: getDummyScaTestResults(true, false), +// }}, +// ExtendedScanResults: dummyExtendedScanResults, +// }, +// expected: formats.SummaryResults{ +// Scans: []formats.ScanSummaryResult{ +// { +// Target: "target1", +// Vulnerabilities: &formats.ScanVulnerabilitiesSummary{ +// ScaScanResults: &formats.ScanScaResult{ +// SummaryCount: formats.TwoLevelSummaryCount{ +// "Critical": formats.SummaryCount{"Undetermined": 1}, +// "High": formats.SummaryCount{"Not Applicable": 1}, +// }, +// UniqueFindings: 2, +// }, +// SecretsScanResults: &formats.SummaryCount{"Low": 2}, +// SastScanResults: &formats.SummaryCount{"Low": 1}, +// }, +// Violations: formats.TwoLevelSummaryCount{}, +// }, +// }, +// }, +// findingCount: 5, +// issueCount: 5, +// }, +// { +// name: "Multiple module results", +// cmdResults: results.ScanCommandResults{ +// ScaResults: []ScaScanResult{ +// { +// Target: "target1", +// XrayResults: getDummyScaTestResults(false, true), +// }, +// { +// Target: "target2", +// XrayResults: getDummyScaTestResults(true, true), +// }, +// }, +// ExtendedScanResults: dummyExtendedScanResults, +// }, +// expected: formats.SummaryResults{ +// Scans: []formats.ScanSummaryResult{ +// { +// Target: "target1", +// Vulnerabilities: &formats.ScanVulnerabilitiesSummary{ +// ScaScanResults: &formats.ScanScaResult{SummaryCount: formats.TwoLevelSummaryCount{}}, +// SecretsScanResults: &formats.SummaryCount{"Low": 1}, +// SastScanResults: &formats.SummaryCount{"Low": 1}, +// }, +// Violations: formats.TwoLevelSummaryCount{ +// formats.ViolationTypeSecurity.String(): formats.SummaryCount{"Critical": 1, "High": 1}, +// formats.ViolationTypeLicense.String(): formats.SummaryCount{"High": 1}, +// }, +// }, +// { +// Target: "target2", +// Vulnerabilities: &formats.ScanVulnerabilitiesSummary{ +// ScaScanResults: &formats.ScanScaResult{ +// SummaryCount: formats.TwoLevelSummaryCount{"Critical": formats.SummaryCount{"": 1}}, +// UniqueFindings: 1, +// }, +// SecretsScanResults: &formats.SummaryCount{"Low": 1}, +// }, +// Violations: formats.TwoLevelSummaryCount{formats.ViolationTypeSecurity.String(): formats.SummaryCount{"High": 1}}, +// }, +// }, +// }, +// findingCount: 7, +// issueCount: 8, +// }, +// } +// for _, testCase := range testCases { +// t.Run(testCase.name, func(t *testing.T) { +// result := testCase.cmdResults.GetSummary() +// assert.Equal(t, testCase.expected, result) +// assert.Equal(t, testCase.findingCount, testCase.cmdResults.CountScanResultsFindings()) +// assert.Equal(t, testCase.issueCount, testCase.cmdResults.GetSummary().GetTotalIssueCount()) +// }) +// } +// } \ No newline at end of file diff --git a/utils/results/conversion/tableparser/tableparser.go b/utils/results/conversion/tableparser/tableparser.go index 70311cce..6e48d054 100644 --- a/utils/results/conversion/tableparser/tableparser.go +++ b/utils/results/conversion/tableparser/tableparser.go @@ -1 +1,68 @@ -package tableparser \ No newline at end of file +package tableparser + +import ( + "github.com/owenrumney/go-sarif/v2/sarif" + + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/results/conversion/simplejsonparser" + "github.com/jfrog/jfrog-cli-security/utils/techutils" + + "github.com/jfrog/jfrog-client-go/xray/services" +) + +type CmdResultsTableConverter struct { + simpleJsonConvertor *simplejsonparser.CmdResultsSimpleJsonConverter + // If supported, pretty print the output in the tables + pretty bool +} + +func NewCmdResultsTableConverter(pretty bool) *CmdResultsTableConverter { + return &CmdResultsTableConverter{pretty: pretty, simpleJsonConvertor: simplejsonparser.NewCmdResultsSimpleJsonConverter(pretty)} +} + +func (tc *CmdResultsTableConverter) Get() *formats.ResultsTables { + simpleJsonFormat := tc.simpleJsonConvertor.Get() + if simpleJsonFormat != nil { + return &formats.ResultsTables{} + } + return &formats.ResultsTables{ + SecurityVulnerabilitiesTable: formats.ConvertToVulnerabilityTableRow(simpleJsonFormat.Vulnerabilities), + LicenseViolationsTable: formats.ConvertToLicenseViolationTableRow(simpleJsonFormat.LicensesViolations), + OperationalRiskViolationsTable: formats.ConvertToOperationalRiskViolationTableRow(simpleJsonFormat.OperationalRiskViolations), + SecretsTable: formats.ConvertToSecretsTableRow(simpleJsonFormat.Secrets), + IacTable: formats.ConvertToIacOrSastTableRow(simpleJsonFormat.Iacs), + SastTable: formats.ConvertToIacOrSastTableRow(simpleJsonFormat.Sast), + } +} + +func (tc *CmdResultsTableConverter) Reset(multiScanId, xrayVersion string, entitledForJas bool) (err error) { + return tc.simpleJsonConvertor.Reset(multiScanId, xrayVersion, entitledForJas) +} + +func (tc *CmdResultsTableConverter) ParseNewScanResultsMetadata(target string, errors error) (err error) { + return tc.simpleJsonConvertor.ParseNewScanResultsMetadata(target, errors) +} + +func (tc *CmdResultsTableConverter) ParseViolations(target string, tech techutils.Technology, violations []services.Violation, applicabilityRuns ...*sarif.Run) (err error) { + return tc.simpleJsonConvertor.ParseViolations(target, tech, violations, applicabilityRuns...) +} + +func (tc *CmdResultsTableConverter) ParseVulnerabilities(target string, tech techutils.Technology, vulnerabilities []services.Vulnerability, applicabilityRuns ...*sarif.Run) (err error) { + return tc.simpleJsonConvertor.ParseVulnerabilities(target, tech, vulnerabilities, applicabilityRuns...) +} + +func (tc *CmdResultsTableConverter) ParseLicenses(target string, tech techutils.Technology, licenses []services.License) (err error) { + return tc.simpleJsonConvertor.ParseLicenses(target, tech, licenses) +} + +func (tc *CmdResultsTableConverter) ParseSecrets(target string, secrets ...*sarif.Run) (err error) { + return tc.simpleJsonConvertor.ParseSecrets(target, secrets...) +} + +func (tc *CmdResultsTableConverter) ParseIacs(target string, iacs ...*sarif.Run) (err error) { + return tc.simpleJsonConvertor.ParseIacs(target, iacs...) +} + +func (tc *CmdResultsTableConverter) ParseSast(target string, sast ...*sarif.Run) (err error) { + return tc.simpleJsonConvertor.ParseSast(target, sast...) +} \ No newline at end of file diff --git a/utils/securityJobSummary.go b/utils/results/output/securityJobSummary.go similarity index 96% rename from utils/securityJobSummary.go rename to utils/results/output/securityJobSummary.go index bfea6497..b90ed815 100644 --- a/utils/securityJobSummary.go +++ b/utils/results/output/securityJobSummary.go @@ -1,4 +1,4 @@ -package utils +package output import ( "fmt" @@ -11,6 +11,7 @@ import ( "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/severityutils" "github.com/jfrog/jfrog-client-go/utils/log" "github.com/jfrog/jfrog-client-go/xray/services" @@ -356,7 +357,7 @@ func updateSummaryNamesToRelativePath(summary *formats.SummaryResults, wd string } } -func getScanSummary(extendedScanResults *ExtendedScanResults, scaResults ...*ScaScanResult) (summary formats.ScanSummaryResult) { +func getScanSummary(extendedScanResults *results.ExtendedScanResults, scaResults ...*results.ScaScanResult) (summary formats.ScanSummaryResult) { if len(scaResults) == 0 { return } @@ -370,7 +371,7 @@ func getScanSummary(extendedScanResults *ExtendedScanResults, scaResults ...*Sca return } -func getScanViolationsSummary(scaResults ...*ScaScanResult) (violations formats.TwoLevelSummaryCount) { +func getScanViolationsSummary(scaResults ...*results.ScaScanResult) (violations formats.TwoLevelSummaryCount) { vioUniqueFindings := map[string]IssueDetails{} if len(scaResults) == 0 { return @@ -396,7 +397,7 @@ func getScanViolationsSummary(scaResults ...*ScaScanResult) (violations formats. return issueDetailsToSummaryCount(vioUniqueFindings) } -func getScanSecurityVulnerabilitiesSummary(extendedScanResults *ExtendedScanResults, scaResults ...*ScaScanResult) (summary *formats.ScanVulnerabilitiesSummary) { +func getScanSecurityVulnerabilitiesSummary(extendedScanResults *results.ExtendedScanResults, scaResults ...*results.ScaScanResult) (summary *formats.ScanVulnerabilitiesSummary) { summary = &formats.ScanVulnerabilitiesSummary{} if extendedScanResults == nil { summary.ScaScanResults = getScaSummaryResults(scaResults) @@ -429,7 +430,7 @@ func getSecurityIssueFindings(cves []services.Cve, issueId string, severity seve for _, cve := range cves { cveId := getCveId(cve, issueId) applicableStatus := jasutils.NotScanned - if applicableInfo := getCveApplicabilityField(cveId, applicableRuns, components); applicableInfo != nil { + if applicableInfo := results.GetCveApplicabilityField(cveId, applicableRuns, components); applicableInfo != nil { applicableStatus = jasutils.ConvertToApplicabilityStatus(applicableInfo.Status) } uniqueFindings[cveId] = IssueDetails{ @@ -443,7 +444,7 @@ func getSecurityIssueFindings(cves []services.Cve, issueId string, severity seve return } -func getScaSummaryResults(scaScanResults []*ScaScanResult, applicableRuns ...*sarif.Run) *formats.ScanScaResult { +func getScaSummaryResults(scaScanResults []*results.ScaScanResult, applicableRuns ...*sarif.Run) *formats.ScanScaResult { vulFindings := map[string]IssueDetails{} vulUniqueFindings := map[string]IssueDetails{} if len(scaScanResults) == 0 { diff --git a/utils/securityJobSummary_test.go b/utils/results/output/securityJobSummary_test.go similarity index 99% rename from utils/securityJobSummary_test.go rename to utils/results/output/securityJobSummary_test.go index e04d3396..259c15c3 100644 --- a/utils/securityJobSummary_test.go +++ b/utils/results/output/securityJobSummary_test.go @@ -1,4 +1,4 @@ -package utils +package output import ( "os" diff --git a/utils/results/results.go b/utils/results/results.go index b9e036f1..10b337b5 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -1,58 +1,133 @@ package results import ( + "errors" + "github.com/jfrog/gofrog/datastructures" - "github.com/jfrog/jfrog-cli-security/utils/formats" - "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-client-go/xray/services" "github.com/owenrumney/go-sarif/v2/sarif" ) +// ScanCommandResults is a struct that holds the results of a security scan/audit command. type ScanCommandResults struct { - ScaResults []*ScaScanResult - XrayVersion string - ScansErr error + // General fields describing the command metadata + XrayVersion string `json:"xray_version"` + EntitledForJas bool `json:"entitledForJas"` + // MultiScanId is a unique identifier that is used to group multiple scans together. + MultiScanId string `json:"multi_scan_id,omitempty"` + // Results for each target in the command + Scans []*ScanResults `json:"scans"` + Errors error `json:"errors,omitempty"` +} + +type ScanTarget struct { + // Physical location of the target: Working directory (audit) / binary to scan (scan / docker scan) + Target string `json:"target,omitempty"` + // Logical name of the target (build name / module name / docker image name...) + Name string `json:"name,omitempty"` + // Optional field (not used only in build scan) to provide the technology of the target + Technology techutils.Technology `json:"technology,omitempty"` +} - ExtendedScanResults *ExtendedScanResults +type ScanResults struct { + ScanTarget + // All scan results for the target + ScaResults []*ScaScanResults `json:"sca_scans,omitempty"` + JasResults *JasScansResults `json:"Jas_scans,omitempty"` + // Scan result error + Error error `json:"errors,omitempty"` +} + +type ScaScanResults struct { + // Related Descriptor that provided the dependencies for the scan + ScanTarget + // Sca scan results + XrayResult services.ScanResponse `json:"XrayScan"` +} - MultiScanId string +type JasScansResults struct { + ApplicabilityScanResults []*sarif.Run `json:"ContextualAnalysis,omitempty"` + SecretsScanResults []*sarif.Run `json:"Secrets,omitempty"` + IacScanResults []*sarif.Run `json:"Iac,omitempty"` + SastScanResults []*sarif.Run `json:"Sast,omitempty"` } -func NewAuditResults() *ScanCommandResults { - return &ScanCommandResults{ExtendedScanResults: &ExtendedScanResults{}} +func NewCommandResults(xrayVersion string, entitledForJas bool) *ScanCommandResults { + return &ScanCommandResults{XrayVersion: xrayVersion, EntitledForJas: entitledForJas} } +func (r *ScanCommandResults) SetMultiScanId(multiScanId string) *ScanCommandResults { + r.MultiScanId = multiScanId + return r +} + +// --- Aggregated results for all targets --- + func (r *ScanCommandResults) GetScaScansXrayResults() (results []services.ScanResponse) { - for _, scaResult := range r.ScaResults { - results = append(results, scaResult.XrayResults...) + for _, scan := range r.Scans { + results = append(results, scan.GetScaScansXrayResults()...) } return } -func (r *ScanCommandResults) GetScaScannedTechnologies() []techutils.Technology { +func (r *ScanCommandResults) GetJasScansResults(scanType jasutils.JasScanType) (results []*sarif.Run) { + if !r.EntitledForJas { + return + } + for _, scan := range r.Scans { + results = append(results, scan.GetJasScansResults(scanType)...) + } + return +} + +func (r *ScanCommandResults) GetErrors() (err error) { + err = r.Errors + for _, scan := range r.Scans { + if scan.Error != nil { + err = errors.Join(err, scan.Error) + } + } + return +} + +func (r *ScanCommandResults) GetTechnologyScaScans(technology techutils.Technology) (scans []*ScaScanResults) { + for _, scan := range r.Scans { + for _, scaResult := range scan.ScaResults { + if scaResult.Technology == technology { + scans = append(scans, scaResult) + } + } + } + return +} + +func (r *ScanCommandResults) GetTechnologies() []techutils.Technology { technologies := datastructures.MakeSet[techutils.Technology]() - for _, scaResult := range r.ScaResults { - technologies.Add(scaResult.Technology) + for _, scan := range r.Scans { + technologies.AddElements(scan.GetTechnologies()...) } return technologies.ToSlice() } -func (r *ScanCommandResults) IsMultipleProject() bool { - if len(r.ScaResults) == 0 { - return false +// In case multipleRoots is true, the field Component will show the root of each impact path, otherwise it will show the root's child. +// Set multipleRoots to true in case the given vulnerabilities array contains (or may contain) results of several projects or files (like in binary scan). +func (r *ScanCommandResults) HasMultipleTargets() bool { + if len(r.Scans) > 1 { + return true } - if len(r.ScaResults) == 1 { - if r.ScaResults[0].IsMultipleRootProject == nil { - return false + for _, scan := range r.Scans { + // If there is more than one SCA scan target (i.e multiple files with dependencies information) + if len(scan.ScaResults) > 1 { + return true } - return *r.ScaResults[0].IsMultipleRootProject } - return true + return false } -func (r *ScanCommandResults) IsScaIssuesFound() bool { - for _, scan := range r.ScaResults { +func (r *ScanCommandResults) HasInformation() bool { + for _, scan := range r.Scans { if scan.HasInformation() { return true } @@ -60,102 +135,272 @@ func (r *ScanCommandResults) IsScaIssuesFound() bool { return false } -func (r *ScanCommandResults) getScaScanResultByTarget(target string) *ScaScanResult { - for _, scan := range r.ScaResults { - if scan.Target == target { - return scan +func (r *ScanCommandResults) HasFindings() bool { + for _, scan := range r.Scans { + if scan.HasFindings() { + return true } } - return nil + return false } -func (r *ScanCommandResults) IsIssuesFound() bool { - if r.IsScaIssuesFound() { - return true - } - if r.ExtendedScanResults.IsIssuesFound() { - return true +// --- Scan on a target --- + +func (r *ScanCommandResults) NewScanResults(target ScanTarget) *ScanResults { + scanResults := &ScanResults{ScanTarget: target} + if r.EntitledForJas { + scanResults.JasResults = &JasScansResults{} } - return false + r.Scans = append(r.Scans, scanResults) + return scanResults } -// Counts the total number of unique findings in the provided results. -// A unique SCA finding is identified by a unique pair of vulnerability's/violation's issueId and component id or by a result returned from one of JAS scans. -func (r *ScanCommandResults) CountScanResultsFindings() (total int) { - return formats.SummaryResults{Scans: r.getScanSummaryByTargets()}.GetTotalIssueCount() -} -func (r *ScanCommandResults) GetSummary() (summary formats.SummaryResults) { - if len(r.ScaResults) <= 1 { - summary.Scans = r.getScanSummaryByTargets() - return - } - for _, scaScan := range r.ScaResults { - summary.Scans = append(summary.Scans, r.getScanSummaryByTargets(scaScan.Target)...) +func (sr *ScanResults) GetScaScansXrayResults() (results []services.ScanResponse) { + for _, scaResult := range sr.ScaResults { + results = append(results, scaResult.XrayResult) } return } -// Returns a summary for the provided targets. If no targets are provided, a summary for all targets is returned. -func (r *ScanCommandResults) getScanSummaryByTargets(targets ...string) (summaries []formats.ScanSummaryResult) { - if len(targets) == 0 { - // No filter, one scan summary for all targets - summaries = append(summaries, getScanSummary(r.ExtendedScanResults, r.ScaResults...)) - return +func (sr *ScanResults) GetTechnologies() []techutils.Technology { + technologies := datastructures.MakeSet[techutils.Technology]() + for _, scaResult := range sr.ScaResults { + technologies.Add(scaResult.Technology) } - for _, target := range targets { - // Get target sca results - targetScaResults := []*ScaScanResult{} - if targetScaResult := r.getScaScanResultByTarget(target); targetScaResult != nil { - targetScaResults = append(targetScaResults, targetScaResult) - } - // Get target extended results - targetExtendedResults := r.ExtendedScanResults - if targetExtendedResults != nil { - targetExtendedResults = targetExtendedResults.GetResultsForTarget(target) - } - summaries = append(summaries, getScanSummary(targetExtendedResults, targetScaResults...)) + return technologies.ToSlice() +} + +func (sr *ScanResults) GetJasScansResults(scanType jasutils.JasScanType) (results []*sarif.Run) { + if sr.JasResults == nil { + return } - return + return sr.JasResults.GetResults(scanType) } -type ScaScanResult struct { - // Could be working directory (audit), file path (binary scan) or build name+number (build scan) - Target string `json:"Target"` - Technology techutils.Technology `json:"Technology,omitempty"` - XrayResults []services.ScanResponse `json:"XrayResults,omitempty"` - Descriptors []string `json:"Descriptors,omitempty"` - IsMultipleRootProject *bool `json:"IsMultipleRootProject,omitempty"` +func (sr *ScanResults) HasInformation() bool { + for _, scaResult := range sr.ScaResults { + if scaResult.HasInformation() { + return true + } + } + return false } -func (s ScaScanResult) HasInformation() bool { - for _, scan := range s.XrayResults { - if len(scan.Vulnerabilities) > 0 || len(scan.Violations) > 0 || len(scan.Licenses) > 0 { +func (sr *ScanResults) HasFindings() bool { + for _, scaResult := range sr.ScaResults { + if scaResult.HasFindings() { return true } } return false } -type ExtendedScanResults struct { - ApplicabilityScanResults []*sarif.Run - SecretsScanResults []*sarif.Run - IacScanResults []*sarif.Run - SastScanResults []*sarif.Run - EntitledForJas bool +func (sr *ScanResults) NewScaScanResults(response *services.ScanResponse) *ScaScanResults { + scaScanResults := NewScaScanResults(response) + sr.ScaResults = append(sr.ScaResults, scaScanResults) + return scaScanResults +} + +func (sr *ScanResults) NewScaScan(target string, technology techutils.Technology) *ScaScanResults { + scaScanResults := &ScaScanResults{ScanTarget: ScanTarget{Target: target, Technology: technology}} + sr.ScaResults = append(sr.ScaResults, scaScanResults) + return scaScanResults +} + +func NewScaScanResults(response *services.ScanResponse) *ScaScanResults { + return &ScaScanResults{XrayResult: *response} +} + +func (ssr *ScaScanResults) SetDescriptor(descriptor string) *ScaScanResults { + ssr.Target = descriptor + return ssr +} + +func (ssr *ScaScanResults) SetTechnology(technology techutils.Technology) *ScaScanResults { + ssr.Technology = technology + return ssr +} + +func (ssr *ScaScanResults) SetXrayScanResults(response *services.ScanResponse) *ScaScanResults { + ssr.XrayResult = *response + return ssr } -func (e *ExtendedScanResults) IsIssuesFound() bool { - return sarifutils.GetResultsLocationCount(e.ApplicabilityScanResults...) > 0 || - sarifutils.GetResultsLocationCount(e.SecretsScanResults...) > 0 || - sarifutils.GetResultsLocationCount(e.IacScanResults...) > 0 || - sarifutils.GetResultsLocationCount(e.SastScanResults...) > 0 +func (ssr *ScaScanResults) HasInformation() bool { + return ssr.HasFindings() || len(ssr.XrayResult.Licenses) > 0 } -func (e *ExtendedScanResults) GetResultsForTarget(target string) (result *ExtendedScanResults) { - return &ExtendedScanResults{ - ApplicabilityScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.ApplicabilityScanResults...), - SecretsScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.SecretsScanResults...), - IacScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.IacScanResults...), - SastScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.SastScanResults...), +func (ssr *ScaScanResults) HasFindings() bool { + return len(ssr.XrayResult.Vulnerabilities) > 0 || len(ssr.XrayResult.Violations) > 0 +} + +func (jsr *JasScansResults) GetResults(scanType jasutils.JasScanType) (results []*sarif.Run) { + switch scanType { + case jasutils.Applicability: + results = jsr.ApplicabilityScanResults + case jasutils.Secrets: + results = jsr.SecretsScanResults + case jasutils.IaC: + results = jsr.IacScanResults + case jasutils.Sast: + results = jsr.SastScanResults } + return } + + + + + + + + + + + + + + + + + +// func NewAuditResults() *ScanCommandResults { +// return &ScanCommandResults{ExtendedScanResults: &ExtendedScanResults{}} +// } + +// func (r *ScanCommandResults) GetScaScansXrayResults() (results []services.ScanResponse) { +// for _, scaResult := range r.ScaResults { +// results = append(results, scaResult.XrayResults...) +// } +// return +// } + +// func (r *ScanCommandResults) GetScaScannedTechnologies() []techutils.Technology { +// technologies := datastructures.MakeSet[techutils.Technology]() +// for _, scaResult := range r.ScaResults { +// technologies.Add(scaResult.Technology) +// } +// return technologies.ToSlice() +// } + +// func (r *ScanCommandResults) IsMultipleProject() bool { +// if len(r.ScaResults) == 0 { +// return false +// } +// if len(r.ScaResults) == 1 { +// if r.ScaResults[0].IsMultipleRootProject == nil { +// return false +// } +// return *r.ScaResults[0].IsMultipleRootProject +// } +// return true +// } + +// func (r *ScanCommandResults) IsScaIssuesFound() bool { +// for _, scan := range r.ScaResults { +// if scan.HasInformation() { +// return true +// } +// } +// return false +// } + +// func (r *ScanCommandResults) getScaScanResultByTarget(target string) *ScaScanResult { +// for _, scan := range r.ScaResults { +// if scan.Target == target { +// return scan +// } +// } +// return nil +// } + +// func (r *ScanCommandResults) IsIssuesFound() bool { +// if r.IsScaIssuesFound() { +// return true +// } +// if r.ExtendedScanResults.IsIssuesFound() { +// return true +// } +// return false +// } + +// // Counts the total number of unique findings in the provided results. +// // A unique SCA finding is identified by a unique pair of vulnerability's/violation's issueId and component id or by a result returned from one of JAS scans. +// func (r *ScanCommandResults) CountScanResultsFindings() (total int) { +// return formats.SummaryResults{Scans: r.getScanSummaryByTargets()}.GetTotalIssueCount() +// } +// func (r *ScanCommandResults) GetSummary() (summary formats.SummaryResults) { +// if len(r.ScaResults) <= 1 { +// summary.Scans = r.getScanSummaryByTargets() +// return +// } +// for _, scaScan := range r.ScaResults { +// summary.Scans = append(summary.Scans, r.getScanSummaryByTargets(scaScan.Target)...) +// } +// return +// } + +// // Returns a summary for the provided targets. If no targets are provided, a summary for all targets is returned. +// func (r *ScanCommandResults) getScanSummaryByTargets(targets ...string) (summaries []formats.ScanSummaryResult) { +// if len(targets) == 0 { +// // No filter, one scan summary for all targets +// summaries = append(summaries, getScanSummary(r.ExtendedScanResults, r.ScaResults...)) +// return +// } +// for _, target := range targets { +// // Get target sca results +// targetScaResults := []*ScaScanResult{} +// if targetScaResult := r.getScaScanResultByTarget(target); targetScaResult != nil { +// targetScaResults = append(targetScaResults, targetScaResult) +// } +// // Get target extended results +// targetExtendedResults := r.ExtendedScanResults +// if targetExtendedResults != nil { +// targetExtendedResults = targetExtendedResults.GetResultsForTarget(target) +// } +// summaries = append(summaries, getScanSummary(targetExtendedResults, targetScaResults...)) +// } +// return +// } + +// type ScaScanResult struct { +// // Could be working directory (audit), file path (binary scan) or build name+number (build scan) +// Target string `json:"Target"` +// Technology techutils.Technology `json:"Technology,omitempty"` +// XrayResults []services.ScanResponse `json:"XrayResults,omitempty"` +// Descriptors []string `json:"Descriptors,omitempty"` +// IsMultipleRootProject *bool `json:"IsMultipleRootProject,omitempty"` +// } + +// func (s ScaScanResult) HasInformation() bool { +// for _, scan := range s.XrayResults { +// if len(scan.Vulnerabilities) > 0 || len(scan.Violations) > 0 || len(scan.Licenses) > 0 { +// return true +// } +// } +// return false +// } + +// type ExtendedScanResults struct { +// ApplicabilityScanResults []*sarif.Run +// SecretsScanResults []*sarif.Run +// IacScanResults []*sarif.Run +// SastScanResults []*sarif.Run +// EntitledForJas bool +// } + +// func (e *ExtendedScanResults) IsIssuesFound() bool { +// return sarifutils.GetResultsLocationCount(e.ApplicabilityScanResults...) > 0 || +// sarifutils.GetResultsLocationCount(e.SecretsScanResults...) > 0 || +// sarifutils.GetResultsLocationCount(e.IacScanResults...) > 0 || +// sarifutils.GetResultsLocationCount(e.SastScanResults...) > 0 +// } + +// func (e *ExtendedScanResults) GetResultsForTarget(target string) (result *ExtendedScanResults) { +// return &ExtendedScanResults{ +// ApplicabilityScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.ApplicabilityScanResults...), +// SecretsScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.SecretsScanResults...), +// IacScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.IacScanResults...), +// SastScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.SastScanResults...), +// } +// } diff --git a/utils/resultstable_test.go b/utils/resultstable_test.go index 87d8c7cc..614776a4 100644 --- a/utils/resultstable_test.go +++ b/utils/resultstable_test.go @@ -1110,18 +1110,3 @@ func TestGetFinalApplicabilityStatus(t *testing.T) { } } -func newBoolPtr(v bool) *bool { - return &v -} - -func newIntPtr(v int) *int { - return &v -} - -func newInt64Ptr(v int64) *int64 { - return &v -} - -func newFloat64Ptr(v float64) *float64 { - return &v -} diff --git a/utils/resultwriter.go b/utils/resultwriter.go index 56982e2d..115b3832 100644 --- a/utils/resultwriter.go +++ b/utils/resultwriter.go @@ -24,10 +24,6 @@ import ( "golang.org/x/exp/slices" ) -const ( - BaseDocumentationURL = "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/" -) - const MissingCveScore = "0" const maxPossibleCve = 10.0 diff --git a/utils/utils.go b/utils/utils.go index 1824bf23..f81f8cfa 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -1,8 +1,19 @@ package utils +import ( + "encoding/json" + + "github.com/jfrog/gofrog/datastructures" + clientUtils "github.com/jfrog/jfrog-client-go/utils" + "github.com/jfrog/jfrog-client-go/utils/errorutils" +) + const ( NodeModulesPattern = "**/*node_modules*/**" JfMsiEnvVariable = "JF_MSI" + + BaseDocumentationURL = "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/" + JasInfoURL = "https://jfrog.com/xray/" ) var ( @@ -29,3 +40,43 @@ func (s SubScanType) String() string { func GetAllSupportedScans() []SubScanType { return []SubScanType{ScaScan, ContextualAnalysisScan, IacScan, SastScan, SecretsScan} } + +// UniqueUnion returns a new slice of strings that contains elements from both input slices without duplicates +func UniqueUnion[T comparable](arr []T, others ...T) []T { + uniqueSet := datastructures.MakeSet[T]() + var result []T + for _, str := range arr { + uniqueSet.Add(str) + result = append(result, str) + } + for _, str := range others { + if exist := uniqueSet.Exists(str); !exist { + result = append(result, str) + } + } + return result +} + +func GetAsJsonString(output interface{}) (string, error) { + results, err := json.Marshal(output) + if err != nil { + return "", errorutils.CheckError(err) + } + return clientUtils.IndentJson(results), nil +} + +func NewBoolPtr(v bool) *bool { + return &v +} + +func NewIntPtr(v int) *int { + return &v +} + +func NewInt64Ptr(v int64) *int64 { + return &v +} + +func NewFloat64Ptr(v float64) *float64 { + return &v +} \ No newline at end of file From fd8e0257bef2b322ecf3be6686bb87ccff3ebe88 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 1 Jul 2024 16:44:22 +0300 Subject: [PATCH 06/82] continue implement --- commands/audit/audit.go | 31 +- commands/audit/scarunner.go | 9 +- commands/scan/buildscan.go | 17 +- utils/results/common.go | 15 +- utils/results/conversion/convertor.go | 2 +- .../conversion/sarifparser/sarifparser.go | 2 +- .../sarifparser/sarifparser_test.go | 2 +- .../simplejsonparser/simplejsonparser.go | 2 +- .../simplejsonparser/simplejsonparser_test.go | 2 +- .../conversion/summaryparser/summaryparser.go | 2 +- .../summaryparser/summaryparser_test.go | 2 +- .../conversion/tableparser/tableparser.go | 2 +- utils/results/output/resultwriter.go | 1 + utils/results/output/securityJobSummary.go | 265 +++++------------- utils/results/results.go | 18 +- utils/results/results_test.go | 12 +- utils/resultstable_test.go | 1 - utils/utils.go | 2 +- utils/xsc/analyticsmetrics.go | 10 +- utils/xsc/analyticsmetrics_test.go | 57 ++-- 20 files changed, 161 insertions(+), 293 deletions(-) create mode 100644 utils/results/output/resultwriter.go diff --git a/commands/audit/audit.go b/commands/audit/audit.go index 91d6a6a4..55692067 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -146,11 +146,11 @@ func (auditCmd *AuditCommand) Run() (err error) { } } var messages []string - if !auditResults.ExtendedScanResults.EntitledForJas { + if !auditResults.EntitledForJas { messages = []string{coreutils.PrintTitle("The ‘jf audit’ command also supports JFrog Advanced Security features, such as 'Contextual Analysis', 'Secret Detection', 'IaC Scan' and ‘SAST’.\nThis feature isn't enabled on your system. Read more - ") + coreutils.PrintLink("https://jfrog.com/xray/")} } if err = utils.NewResultsWriter(auditResults). - SetIsMultipleRootProject(auditResults.IsMultipleProject()). + SetIsMultipleRootProject(auditResults.HasMultipleTargets()). SetIncludeVulnerabilities(auditCmd.IncludeVulnerabilities). SetIncludeLicenses(auditCmd.IncludeLicenses). SetOutputFormat(auditCmd.OutputFormat()). @@ -162,8 +162,8 @@ func (auditCmd *AuditCommand) Run() (err error) { return } - if auditResults.ScansErr != nil { - return auditResults.ScansErr + if err = auditResults.GetErrors(); err != nil { + return } // Only in case Xray's context was given (!auditCmd.IncludeVulnerabilities), and the user asked to fail the build accordingly, do so. @@ -181,8 +181,7 @@ func (auditCmd *AuditCommand) CommandName() string { // Returns an audit Results object containing all the scan results. // If the current server is entitled for JAS, the advanced security results will be included in the scan results. func RunAudit(auditParams *AuditParams) (cmdResults *results.ScanCommandResults, err error) { - // Initialize Results struct - cmdResults = results.NewAuditResults() + // Prepare serverDetails, err := auditParams.ServerDetails() if err != nil { return @@ -194,12 +193,12 @@ func RunAudit(auditParams *AuditParams) (cmdResults *results.ScanCommandResults, if err = clientutils.ValidateMinimumVersion(clientutils.Xray, auditParams.xrayVersion, scangraph.GraphScanMinXrayVersion); err != nil { return } - cmdResults.XrayVersion = auditParams.xrayVersion - cmdResults.ExtendedScanResults.EntitledForJas, err = isEntitledForJas(xrayManager, auditParams) + entitledForJas, err := isEntitledForJas(xrayManager, auditParams) if err != nil { return } - cmdResults.MultiScanId = auditParams.commonGraphScanParams.MultiScanId + // Initialize Results struct + cmdResults = results.NewCommandResults(auditParams.xrayVersion, entitledForJas).SetMultiScanId(auditParams.commonGraphScanParams.MultiScanId) auditParallelRunner := utils.CreateSecurityParallelRunner(auditParams.threads) auditParallelRunner.ErrWg.Add(1) @@ -208,7 +207,7 @@ func RunAudit(auditParams *AuditParams) (cmdResults *results.ScanCommandResults, return cmdResults, fmt.Errorf("failed to create JFrogAppsConfig: %s", err.Error()) } jasScanner := &jas.JasScanner{} - if cmdResults.ExtendedScanResults.EntitledForJas { + if cmdResults.EntitledForJas { // Download (if needed) the analyzer manager and run scanners. auditParallelRunner.JasWg.Add(1) if _, jasErr := auditParallelRunner.Runner.AddTaskWithError(func(threadId int) error { @@ -217,7 +216,9 @@ func RunAudit(auditParams *AuditParams) (cmdResults *results.ScanCommandResults, auditParallelRunner.AddErrorToChan(fmt.Errorf("failed to create AM downloading task, skipping JAS scans...: %s", jasErr.Error())) } } - + if auditParams.Progress() != nil { + auditParams.Progress().SetHeadlineMsg("Scanning for issues") + } // The sca scan doesn't require the analyzer manager, so it can run separately from the analyzer manager download routine. if scaScanErr := buildDepTreeAndRunScaScan(auditParallelRunner, auditParams, cmdResults); scaScanErr != nil { auditParallelRunner.AddErrorToChan(scaScanErr) @@ -237,13 +238,11 @@ func RunAudit(auditParams *AuditParams) (cmdResults *results.ScanCommandResults, // a new routine that collects errors from the err channel into results object go func() { defer auditParallelRunner.ErrWg.Done() + // TODO: assign error to correct scan for e := range auditParallelRunner.ErrorsQueue { - cmdResults.ScansErr = errors.Join(cmdResults.ScansErr, e) + cmdResults.Errors = errors.Join(cmdResults.Errors, e) } }() - if auditParams.Progress() != nil { - auditParams.Progress().SetHeadlineMsg("Scanning for issues") - } auditParallelRunner.Runner.Run() auditParallelRunner.ErrWg.Wait() return @@ -269,7 +268,7 @@ func downloadAnalyzerManagerAndRunScanners(auditParallelRunner *utils.SecurityPa if err != nil { return fmt.Errorf("failed to create jas scanner: %s", err.Error()) } - if err = runner.AddJasScannersTasks(auditParallelRunner, scanResults, scanResults.GetScaScannedTechnologies(), auditParams.DirectDependencies(), serverDetails, auditParams.thirdPartyApplicabilityScan, auditParams.commonGraphScanParams.MultiScanId, scanner, applicability.ApplicabilityScannerType, secrets.SecretsScannerType, auditParallelRunner.AddErrorToChan, auditParams.ScansToPerform()); err != nil { + if err = runner.AddJasScannersTasks(auditParallelRunner, scanResults, scanResults.GetTechnologies(), auditParams.DirectDependencies(), serverDetails, auditParams.thirdPartyApplicabilityScan, auditParams.commonGraphScanParams.MultiScanId, scanner, applicability.ApplicabilityScannerType, secrets.SecretsScannerType, auditParallelRunner.AddErrorToChan, auditParams.ScansToPerform()); err != nil { return fmt.Errorf("%s failed to run JAS scanners: %s", clientutils.GetLogMsgPrefix(threadId, false), err.Error()) } return diff --git a/commands/audit/scarunner.go b/commands/audit/scarunner.go index 6ba78fda..06002224 100644 --- a/commands/audit/scarunner.go +++ b/commands/audit/scarunner.go @@ -69,6 +69,9 @@ func buildDepTreeAndRunScaScan(auditParallelRunner *utils.SecurityParallelRunner err = errors.Join(err, os.Chdir(currentWorkingDir)) }() for _, scan := range scans { + // Create sub scan + cmdResults.NewScanResults(results.ScanTarget{Target: scan}) + // Get the dependency tree for the technology in the working directory. treeResult, bdtErr := buildDependencyTree(scan, auditParams) if bdtErr != nil { @@ -92,7 +95,7 @@ func buildDepTreeAndRunScaScan(auditParallelRunner *utils.SecurityParallelRunner } // Calculate the scans to preform -func getScaScansToPreform(params *AuditParams) (scansToPreform []*results.ScaScanResult) { +func getScaScansToPreform(params *AuditParams) (scansToPreform []*results.ScanTarget) { for _, requestedDirectory := range params.workingDirs { if !fileutils.IsPathExists(requestedDirectory, false) { log.Warn("The working directory", requestedDirectory, "doesn't exist. Skipping SCA scan...") @@ -113,11 +116,11 @@ func getScaScansToPreform(params *AuditParams) (scansToPreform []*results.ScaSca } if len(workingDirs) == 0 { // Requested technology (from params) descriptors/indicators was not found, scan only requested directory for this technology. - scansToPreform = append(scansToPreform, &results.ScaScanResult{Target: requestedDirectory, Technology: tech}) + scansToPreform = append(scansToPreform, &results.ScanTarget{Target: requestedDirectory, Technology: tech}) } for workingDir, descriptors := range workingDirs { // Add scan for each detected working directory. - scansToPreform = append(scansToPreform, &results.ScaScanResult{Target: workingDir, Technology: tech, Descriptors: descriptors}) + scansToPreform = append(scansToPreform, &results.ScanTarget{Target: workingDir, Technology: tech, Descriptors: descriptors}) } } } diff --git a/commands/scan/buildscan.go b/commands/scan/buildscan.go index f5d2009b..57076f0d 100644 --- a/commands/scan/buildscan.go +++ b/commands/scan/buildscan.go @@ -9,6 +9,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/results/output" xrayutils "github.com/jfrog/jfrog-cli-security/utils/xray" clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/log" @@ -111,7 +112,7 @@ func (bsc *BuildScanCommand) Run() (err error) { } // If failBuild flag is true and also got fail build response from Xray if bsc.failBuild && isFailBuildResponse { - return utils.NewFailBuildError() + return results.NewFailBuildError() } return } @@ -124,17 +125,15 @@ func (bsc *BuildScanCommand) runBuildScanAndPrintResults(xrayManager *xray.XrayS log.Info("The scan data is available at: " + buildScanResults.MoreDetailsUrl) isFailBuildResponse = buildScanResults.FailBuild - scanResponse := []services.ScanResponse{{ + cmdResults := results.NewCommandResults(xrayVersion, false) + scanResults := cmdResults.NewScanResults(results.ScanTarget{Name: fmt.Sprintf("%s (%s)", params.BuildName, params.BuildNumber)}) + scanResults.NewScaScanResults(&services.ScanResponse{ Violations: buildScanResults.Violations, Vulnerabilities: buildScanResults.Vulnerabilities, XrayDataUrl: buildScanResults.MoreDetailsUrl, - }} + }) - scanResults := results.NewAuditResults() - scanResults.XrayVersion = xrayVersion - scanResults.ScaResults = []*results.ScaScanResult{{Target: fmt.Sprintf("%s (%s)", params.BuildName, params.BuildNumber), XrayResults: scanResponse}} - - resultsPrinter := utils.NewResultsWriter(scanResults). + resultsPrinter := utils.NewResultsWriter(cmdResults). SetOutputFormat(bsc.outputFormat). SetIncludeVulnerabilities(bsc.includeVulnerabilities). SetIncludeLicenses(false). @@ -164,7 +163,7 @@ func (bsc *BuildScanCommand) runBuildScanAndPrintResults(xrayManager *xray.XrayS } } } - err = utils.RecordSecurityCommandOutput(utils.ScanCommandSummaryResult{Results: scanResults.GetSummary(), Section: utils.Build}) + err = output.RecordSecurityCommandOutput(output.Build, cmdResults) return } diff --git a/utils/results/common.go b/utils/results/common.go index 6a88f450..7c3ab6e3 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -411,17 +411,16 @@ func getImpactPathKey(path []services.ImpactPathNode) string { return key } -func SplitScaScanResults(results *ScaScanResult) ([]services.Violation, []services.Vulnerability, []services.License) { +func SplitScaScanResults(results *ScanCommandResults) ([]services.Violation, []services.Vulnerability, []services.License) { var violations []services.Violation var vulnerabilities []services.Vulnerability var licenses []services.License - for _, scan := range results.XrayResults { - licenses = append(licenses, scan.Licenses...) - // for _, scaScan := range scan.ScaResults { - // violations = append(violations, scaScan.XrayResult.Violations...) - // vulnerabilities = append(vulnerabilities, scaScan.XrayResult.Vulnerabilities...) - // licenses = append(licenses, scaScan.XrayResult.Licenses...) - // } + for _, scan := range results.Scans { + for _, scaScan := range scan.ScaResults { + violations = append(violations, scaScan.XrayResult.Violations...) + vulnerabilities = append(vulnerabilities, scaScan.XrayResult.Vulnerabilities...) + licenses = append(licenses, scaScan.XrayResult.Licenses...) + } } return violations, vulnerabilities, licenses } diff --git a/utils/results/conversion/convertor.go b/utils/results/conversion/convertor.go index c77b7e93..754ca532 100644 --- a/utils/results/conversion/convertor.go +++ b/utils/results/conversion/convertor.go @@ -248,4 +248,4 @@ func simplifyVulnerabilities(scanVulnerabilities []services.Vulnerability, multi // GetUniqueKey returns a unique string key of format "vulnerableDependency:vulnerableVersion:xrayID:fixVersionExist" func GetUniqueKey(vulnerableDependency, vulnerableVersion, xrayID string, fixVersionExist bool) string { return strings.Join([]string{vulnerableDependency, vulnerableVersion, xrayID, strconv.FormatBool(fixVersionExist)}, ":") -} \ No newline at end of file +} diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index bc899c9c..f9aa478c 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -383,4 +383,4 @@ func getScaLicenseViolationMarkdown(depName, version, key string, directDependen return "", err } return fmt.Sprintf("**The following direct dependencies are utilizing the `%s %s` dependency with `%s` license violation:**\n%s", depName, version, key, formattedDirectDependencies), nil -} \ No newline at end of file +} diff --git a/utils/results/conversion/sarifparser/sarifparser_test.go b/utils/results/conversion/sarifparser/sarifparser_test.go index 56c91810..25781604 100644 --- a/utils/results/conversion/sarifparser/sarifparser_test.go +++ b/utils/results/conversion/sarifparser/sarifparser_test.go @@ -203,4 +203,4 @@ func TestGetScaLicenseViolationMarkdown(t *testing.T) { assert.Equal(t, tc.expectedOutput, output) }) } -} \ No newline at end of file +} diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go index 626b8b0d..1427f6fa 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go @@ -445,4 +445,4 @@ func getOperationalRiskViolationReadableData(violation services.Violation) *oper latestVersion: latestVersion, newerVersions: newerVersions, } -} \ No newline at end of file +} diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go index fe262f78..ab0e2ff8 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go @@ -502,4 +502,4 @@ func TestPrepareSimpleJsonLicenses(t *testing.T) { func TestPrepareSimpleJsonJasIssues(t *testing.T) { -} \ No newline at end of file +} diff --git a/utils/results/conversion/summaryparser/summaryparser.go b/utils/results/conversion/summaryparser/summaryparser.go index 02083f62..b3b08983 100644 --- a/utils/results/conversion/summaryparser/summaryparser.go +++ b/utils/results/conversion/summaryparser/summaryparser.go @@ -211,4 +211,4 @@ func (sc *CmdResultsSummaryConverter) getJasHandler(scanType jasutils.JasScanTyp (*count)[severity.String()]++ return } -} \ No newline at end of file +} diff --git a/utils/results/conversion/summaryparser/summaryparser_test.go b/utils/results/conversion/summaryparser/summaryparser_test.go index d7f957f3..27670226 100644 --- a/utils/results/conversion/summaryparser/summaryparser_test.go +++ b/utils/results/conversion/summaryparser/summaryparser_test.go @@ -163,4 +163,4 @@ func TestGetCveIds(t *testing.T) { // assert.Equal(t, testCase.issueCount, testCase.cmdResults.GetSummary().GetTotalIssueCount()) // }) // } -// } \ No newline at end of file +// } diff --git a/utils/results/conversion/tableparser/tableparser.go b/utils/results/conversion/tableparser/tableparser.go index 6e48d054..5d479d85 100644 --- a/utils/results/conversion/tableparser/tableparser.go +++ b/utils/results/conversion/tableparser/tableparser.go @@ -65,4 +65,4 @@ func (tc *CmdResultsTableConverter) ParseIacs(target string, iacs ...*sarif.Run) func (tc *CmdResultsTableConverter) ParseSast(target string, sast ...*sarif.Run) (err error) { return tc.simpleJsonConvertor.ParseSast(target, sast...) -} \ No newline at end of file +} diff --git a/utils/results/output/resultwriter.go b/utils/results/output/resultwriter.go new file mode 100644 index 00000000..9a40c32a --- /dev/null +++ b/utils/results/output/resultwriter.go @@ -0,0 +1 @@ +package output \ No newline at end of file diff --git a/utils/results/output/securityJobSummary.go b/utils/results/output/securityJobSummary.go index b90ed815..1771090a 100644 --- a/utils/results/output/securityJobSummary.go +++ b/utils/results/output/securityJobSummary.go @@ -9,13 +9,10 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/commandsummary" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-security/utils/formats" - "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/results/conversion" "github.com/jfrog/jfrog-cli-security/utils/severityutils" - "github.com/jfrog/jfrog-client-go/utils/log" - "github.com/jfrog/jfrog-client-go/xray/services" - "github.com/owenrumney/go-sarif/v2/sarif" "golang.org/x/exp/maps" ) @@ -25,6 +22,28 @@ const ( Modules SecuritySummarySection = "Modules" ) +var ( + // Convert summary of the given keys to the needed string + summaryContentToFormatString = map[string]string{ + severityutils.Critical.String(): `❗️ %d ` + severityutils.Critical.String() + ``, + severityutils.High.String(): `🔴 %d ` + severityutils.High.String() + ``, + severityutils.Medium.String(): `🟠 %d ` + severityutils.Medium.String() + ``, + severityutils.Low.String(): `🟡 %d ` + severityutils.Low.String() + ``, + severityutils.Unknown.String(): `⚪️ %d ` + severityutils.Unknown.String() + ``, + jasutils.Applicable.String(): "%d " + jasutils.Applicable.String(), + jasutils.NotApplicable.String(): "%d " + jasutils.NotApplicable.String(), + formats.ViolationTypeSecurity.String(): "%d Security", + formats.ViolationTypeLicense.String(): "%d License", + formats.ViolationTypeOperationalRisk.String(): "%d Operational", + } + // AllowedSorted is the order of the keys to display in the summary + allowedSorted = []string{ + severityutils.Critical.String(), severityutils.High.String(), severityutils.Medium.String(), severityutils.Low.String(), severityutils.Unknown.String(), + jasutils.Applicable.String(), jasutils.NotApplicable.String(), + formats.ViolationTypeSecurity.String(), formats.ViolationTypeLicense.String(), formats.ViolationTypeOperationalRisk.String(), + } +) + type SecuritySummarySection string type ScanCommandSummaryResult struct { @@ -44,8 +63,20 @@ func SecurityCommandsJobSummary() (js *commandsummary.CommandSummary, err error) return commandsummary.New(&SecurityCommandsSummary{}, "security") } +func CreateCommandSummaryResult(section SecuritySummarySection, cmdResults *results.ScanCommandResults) (ScanCommandSummaryResult, error) { + convertor := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{}) + summary, err := convertor.ConvertToSummary(cmdResults) + if err != nil { + return ScanCommandSummaryResult{Section: section}, err + } + return ScanCommandSummaryResult{ + Section: section, + Results: summary, + }, nil +} + // Record the security command output -func RecordSecurityCommandOutput(content ScanCommandSummaryResult) (err error) { +func RecordSecurityCommandOutput(section SecuritySummarySection, cmdResults *results.ScanCommandResults) (err error) { if !commandsummary.ShouldRecordSummary() { return } @@ -57,8 +88,12 @@ func RecordSecurityCommandOutput(content ScanCommandSummaryResult) (err error) { if err != nil { return } - content.WorkingDirectory = wd - return manager.Record(content) + summary, err := CreateCommandSummaryResult(section, cmdResults) + if err != nil { + return + } + summary.WorkingDirectory = wd + return manager.Record(summary) } func (scs *SecurityCommandsSummary) GenerateMarkdownFromFiles(dataFilePaths []string) (markdown string, err error) { @@ -75,11 +110,18 @@ func loadContentFromFiles(dataFilePaths []string, scs *SecurityCommandsSummary) if err = commandsummary.UnmarshalFromFilePath(dataFilePath, &cmdResults); err != nil { return fmt.Errorf("failed while Unmarshal '%s': %w", dataFilePath, err) } - results := cmdResults.Results + scs.addCommandSummaryResult(cmdResults) + } + return +} + +func (scs *SecurityCommandsSummary) addCommandSummaryResult(cmdResults ...ScanCommandSummaryResult) { + for _, cmdResult := range cmdResults { + results := cmdResult.Results // Update the working directory - updateSummaryNamesToRelativePath(&results, cmdResults.WorkingDirectory) + updateSummaryNamesToRelativePath(&results, cmdResult.WorkingDirectory) // Append the new data - switch cmdResults.Section { + switch cmdResult.Section { case Build: scs.BuildScanCommands = append(scs.BuildScanCommands, results) case Binary: @@ -88,7 +130,21 @@ func loadContentFromFiles(dataFilePaths []string, scs *SecurityCommandsSummary) scs.AuditCommands = append(scs.AuditCommands, results) } } - return +} + +func updateSummaryNamesToRelativePath(summary *formats.SummaryResults, wd string) { + for i, scan := range summary.Scans { + if scan.Target == "" { + continue + } + if !strings.HasPrefix(scan.Target, wd) { + continue + } + if scan.Target == wd { + summary.Scans[i].Target = filepath.Base(wd) + } + summary.Scans[i].Target = strings.TrimPrefix(scan.Target, wd) + } } func (scs *SecurityCommandsSummary) GetOrderedSectionsWithContent() (sections []SecuritySummarySection) { @@ -285,28 +341,6 @@ func GetScaSummaryCountString(summary formats.ScanScaResult, padding int) (conte return } -var ( - // Convert summary of the given keys to the needed string - summaryContentToFormatString = map[string]string{ - "Critical": `❗️ %d Critical`, - "High": `🔴 %d High`, - "Medium": `🟠 %d Medium`, - "Low": `🟡 %d Low`, - "Unknown": `⚪️ %d Unknown`, - jasutils.Applicable.String(): "%d " + jasutils.Applicable.String(), - jasutils.NotApplicable.String(): "%d " + jasutils.NotApplicable.String(), - formats.ViolationTypeSecurity.String(): "%d Security", - formats.ViolationTypeLicense.String(): "%d License", - formats.ViolationTypeOperationalRisk.String(): "%d Operational", - } - // AllowedSorted is the order of the keys to display in the summary - allowedSorted = []string{ - "Critical", "High", "Medium", "Low", "Unknown", - jasutils.Applicable.String(), jasutils.NotApplicable.String(), - formats.ViolationTypeSecurity.String(), formats.ViolationTypeLicense.String(), formats.ViolationTypeOperationalRisk.String(), - } -) - func getSummarySortedKeysToDisplay(keys ...string) (sorted []string) { if len(keys) == 0 { return @@ -341,168 +375,3 @@ func GetSummaryContentString(summary formats.SummaryCount, delimiter string, wra } return } - -func updateSummaryNamesToRelativePath(summary *formats.SummaryResults, wd string) { - for i, scan := range summary.Scans { - if scan.Target == "" { - continue - } - if !strings.HasPrefix(scan.Target, wd) { - continue - } - if scan.Target == wd { - summary.Scans[i].Target = filepath.Base(wd) - } - summary.Scans[i].Target = strings.TrimPrefix(scan.Target, wd) - } -} - -func getScanSummary(extendedScanResults *results.ExtendedScanResults, scaResults ...*results.ScaScanResult) (summary formats.ScanSummaryResult) { - if len(scaResults) == 0 { - return - } - if len(scaResults) == 1 { - summary.Target = scaResults[0].Target - } - // Parse violations - summary.Violations = getScanViolationsSummary(scaResults...) - // Parse vulnerabilities - summary.Vulnerabilities = getScanSecurityVulnerabilitiesSummary(extendedScanResults, scaResults...) - return -} - -func getScanViolationsSummary(scaResults ...*results.ScaScanResult) (violations formats.TwoLevelSummaryCount) { - vioUniqueFindings := map[string]IssueDetails{} - if len(scaResults) == 0 { - return - } - // Parse unique findings - for _, scaResult := range scaResults { - for _, xrayResult := range scaResult.XrayResults { - for _, violation := range xrayResult.Violations { - details := IssueDetails{FirstLevelValue: violation.ViolationType, SecondLevelValue: severityutils.GetSeverity(violation.Severity).String()} - for compId := range violation.Components { - if violation.ViolationType == formats.ViolationTypeSecurity.String() { - for _, cve := range violation.Cves { - vioUniqueFindings[getCveId(cve, violation.IssueId)+compId] = details - } - } else { - vioUniqueFindings[violation.IssueId+compId] = details - } - } - } - } - } - // Aggregate - return issueDetailsToSummaryCount(vioUniqueFindings) -} - -func getScanSecurityVulnerabilitiesSummary(extendedScanResults *results.ExtendedScanResults, scaResults ...*results.ScaScanResult) (summary *formats.ScanVulnerabilitiesSummary) { - summary = &formats.ScanVulnerabilitiesSummary{} - if extendedScanResults == nil { - summary.ScaScanResults = getScaSummaryResults(scaResults) - return - } - if len(scaResults) > 0 { - summary.ScaScanResults = getScaSummaryResults(scaResults, extendedScanResults.ApplicabilityScanResults...) - } - summary.IacScanResults = getJASSummaryCount(extendedScanResults.IacScanResults...) - summary.SecretsScanResults = getJASSummaryCount(extendedScanResults.SecretsScanResults...) - summary.SastScanResults = getJASSummaryCount(extendedScanResults.SastScanResults...) - return -} - -type IssueDetails struct { - FirstLevelValue string - SecondLevelValue string -} - -func getCveId(cve services.Cve, defaultIssueId string) string { - if cve.Id == "" { - return defaultIssueId - } - return cve.Id -} - -func getSecurityIssueFindings(cves []services.Cve, issueId string, severity severityutils.Severity, components map[string]services.Component, applicableRuns ...*sarif.Run) (findings, uniqueFindings map[string]IssueDetails) { - findings = map[string]IssueDetails{} - uniqueFindings = map[string]IssueDetails{} - for _, cve := range cves { - cveId := getCveId(cve, issueId) - applicableStatus := jasutils.NotScanned - if applicableInfo := results.GetCveApplicabilityField(cveId, applicableRuns, components); applicableInfo != nil { - applicableStatus = jasutils.ConvertToApplicabilityStatus(applicableInfo.Status) - } - uniqueFindings[cveId] = IssueDetails{ - FirstLevelValue: severity.String(), - SecondLevelValue: applicableStatus.String(), - } - for compId := range components { - findings[cveId+compId] = uniqueFindings[cveId] - } - } - return -} - -func getScaSummaryResults(scaScanResults []*results.ScaScanResult, applicableRuns ...*sarif.Run) *formats.ScanScaResult { - vulFindings := map[string]IssueDetails{} - vulUniqueFindings := map[string]IssueDetails{} - if len(scaScanResults) == 0 { - return nil - } - // Aggregate unique findings - for _, scaResult := range scaScanResults { - for _, xrayResult := range scaResult.XrayResults { - for _, vulnerability := range xrayResult.Vulnerabilities { - vulFinding, vulUniqueFinding := getSecurityIssueFindings(vulnerability.Cves, vulnerability.IssueId, severityutils.GetSeverity(vulnerability.Severity), vulnerability.Components, applicableRuns...) - for key, value := range vulFinding { - vulFindings[key] = value - } - for key, value := range vulUniqueFinding { - vulUniqueFindings[key] = value - } - } - } - } - return &formats.ScanScaResult{ - SummaryCount: issueDetailsToSummaryCount(vulFindings), - UniqueFindings: issueDetailsToSummaryCount(vulUniqueFindings).GetTotal(), - } -} - -func issueDetailsToSummaryCount(uniqueFindings map[string]IssueDetails) formats.TwoLevelSummaryCount { - summary := formats.TwoLevelSummaryCount{} - for _, details := range uniqueFindings { - if _, ok := summary[details.FirstLevelValue]; !ok { - summary[details.FirstLevelValue] = formats.SummaryCount{} - } - summary[details.FirstLevelValue][details.SecondLevelValue]++ - } - return summary -} - -func getJASSummaryCount(runs ...*sarif.Run) *formats.SummaryCount { - if len(runs) == 0 { - return nil - } - count := formats.SummaryCount{} - issueToSeverity := map[string]string{} - for _, run := range runs { - for _, result := range run.Results { - for _, location := range result.Locations { - resultLevel := sarifutils.GetResultLevel(result) - severity, err := severityutils.ParseSeverity(resultLevel, true) - if err != nil { - log.Warn(fmt.Sprintf("Failed to parse Sarif level %s. %s", resultLevel, err.Error())) - severity = severityutils.Unknown - } - severityutils.GetSeverity(sarifutils.GetResultLevel(result)) - issueToSeverity[sarifutils.GetLocationId(location)] = severity.String() - } - } - } - for _, severity := range issueToSeverity { - count[severity]++ - } - return &count -} diff --git a/utils/results/results.go b/utils/results/results.go index 10b337b5..ed884a30 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -35,7 +35,7 @@ type ScanResults struct { ScanTarget // All scan results for the target ScaResults []*ScaScanResults `json:"sca_scans,omitempty"` - JasResults *JasScansResults `json:"Jas_scans,omitempty"` + JasResults *JasScansResults `json:"jas_scans,omitempty"` // Scan result error Error error `json:"errors,omitempty"` } @@ -248,22 +248,6 @@ func (jsr *JasScansResults) GetResults(scanType jasutils.JasScanType) (results [ return } - - - - - - - - - - - - - - - - // func NewAuditResults() *ScanCommandResults { // return &ScanCommandResults{ExtendedScanResults: &ExtendedScanResults{}} // } diff --git a/utils/results/results_test.go b/utils/results/results_test.go index 5117f0d4..38b4fc3c 100644 --- a/utils/results/results_test.go +++ b/utils/results/results_test.go @@ -14,10 +14,10 @@ func TestGetScaScanResultByTarget(t *testing.T) { target1 := &ScaScanResult{Target: "target1"} target2 := &ScaScanResult{Target: "target2"} testCases := []struct { - name string - cmdResults ScanCommandResults - target string - expected *ScaScanResult + name string + cmdResults ScanCommandResults + target string + expected *ScaScanResult }{ { name: "Sca scan result by target", @@ -74,14 +74,14 @@ func TestGetSummary(t *testing.T) { testCases := []struct { name string - cmdResults ScanCommandResults + cmdResults ScanCommandResults expected formats.SummaryResults findingCount int issueCount int }{ { name: "Empty results", - cmdResults: ScanCommandResults{ScaResults: []*ScaScanResult{}}, + cmdResults: ScanCommandResults{ScaResults: []*ScaScanResult{}}, expected: formats.SummaryResults{Scans: []formats.ScanSummaryResult{{}}}, findingCount: 0, issueCount: 0, diff --git a/utils/resultstable_test.go b/utils/resultstable_test.go index 614776a4..3de0a309 100644 --- a/utils/resultstable_test.go +++ b/utils/resultstable_test.go @@ -1109,4 +1109,3 @@ func TestGetFinalApplicabilityStatus(t *testing.T) { }) } } - diff --git a/utils/utils.go b/utils/utils.go index f81f8cfa..16266157 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -79,4 +79,4 @@ func NewInt64Ptr(v int64) *int64 { func NewFloat64Ptr(v float64) *float64 { return &v -} \ No newline at end of file +} diff --git a/utils/xsc/analyticsmetrics.go b/utils/xsc/analyticsmetrics.go index 8e6c253f..e60d66f0 100644 --- a/utils/xsc/analyticsmetrics.go +++ b/utils/xsc/analyticsmetrics.go @@ -10,6 +10,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/usage" "github.com/jfrog/jfrog-cli-security/jas" "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/results/conversion" clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/log" "github.com/jfrog/jfrog-client-go/xsc" @@ -160,13 +161,16 @@ func (ams *AnalyticsMetricsService) GetGeneralEvent(msi string) (*xscservices.Xs func (ams *AnalyticsMetricsService) CreateXscAnalyticsGeneralEventFinalizeFromAuditResults(auditResults *results.ScanCommandResults) *xscservices.XscAnalyticsGeneralEventFinalize { totalDuration := time.Since(ams.GetStartTime()) eventStatus := xscservices.Completed - if auditResults.ScansErr != nil { + if auditResults.GetErrors() != nil { eventStatus = xscservices.Failed } - + summary, err := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{}).ConvertToSummary(auditResults) + if err != nil { + log.Warn(fmt.Sprintf("Failed to convert audit results to summary. %s", err.Error())) + } basicEvent := xscservices.XscAnalyticsBasicGeneralEvent{ EventStatus: eventStatus, - TotalFindings: auditResults.CountScanResultsFindings(), + TotalFindings: summary.GetTotalIssueCount(), TotalScanDuration: totalDuration.String(), } return &xscservices.XscAnalyticsGeneralEventFinalize{ diff --git a/utils/xsc/analyticsmetrics_test.go b/utils/xsc/analyticsmetrics_test.go index 3f7cb2cd..0ecf53a7 100644 --- a/utils/xsc/analyticsmetrics_test.go +++ b/utils/xsc/analyticsmetrics_test.go @@ -77,35 +77,16 @@ func TestAddGeneralEvent(t *testing.T) { func TestAnalyticsMetricsService_createAuditResultsFromXscAnalyticsBasicGeneralEvent(t *testing.T) { usageCallback := tests.SetEnvWithCallbackAndAssert(t, coreutils.ReportUsage, "true") defer usageCallback() - vulnerabilities := []services.Vulnerability{{IssueId: "XRAY-ID", Cves: []services.Cve{{Id: "CVE-123"}}, Components: map[string]services.Component{"issueId_2_direct_dependency": {}}}} - scaResults := []*results.ScaScanResult{{XrayResults: []services.ScanResponse{{Vulnerabilities: vulnerabilities}}}} - auditResults := results.ScanCommandResults{ - ScaResults: scaResults, - ExtendedScanResults: &results.ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyPassingResult("applic_CVE-123"))}, - SecretsScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("", 0, 0, 0, 0, ""))), - sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("", 1, 1, 1, 1, ""))), - }, - IacScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("", 0, 0, 0, 0, ""))), - sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("", 1, 1, 1, 1, ""))), - }, - SastScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("", 0, 0, 0, 0, ""))), - sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("", 1, 1, 1, 1, ""))), - }, - }, - } + testStruct := []struct { name string auditResults *results.ScanCommandResults want xscservices.XscAnalyticsBasicGeneralEvent }{ {name: "No audit results", auditResults: &results.ScanCommandResults{}, want: xscservices.XscAnalyticsBasicGeneralEvent{EventStatus: xscservices.Completed}}, - {name: "Valid audit result", auditResults: &auditResults, want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 7, EventStatus: xscservices.Completed}}, - {name: "Scan failed because jas errors.", auditResults: &results.ScanCommandResults{ScansErr: errors.New("jas error"), ScaResults: scaResults}, want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 1, EventStatus: xscservices.Failed}}, - {name: "Scan failed because sca errors.", auditResults: &results.ScanCommandResults{ScansErr: errors.New("sca error")}, want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 0, EventStatus: xscservices.Failed}}, + {name: "Valid audit result", auditResults: getDummyContentForGeneralEvent(true, false), want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 7, EventStatus: xscservices.Completed}}, + {name: "Scan failed with findings.", auditResults: getDummyContentForGeneralEvent(false, true), want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 1, EventStatus: xscservices.Failed}}, + {name: "Scan failed no findings.", auditResults: &results.ScanCommandResults{Scans: []*results.ScanResults{{Error: errors.New("an error")}}}, want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 0, EventStatus: xscservices.Failed}}, } mockServer, serverDetails := utils.XscServer(t, xscservices.AnalyticsMetricsMinXscVersion) defer mockServer.Close() @@ -123,3 +104,33 @@ func TestAnalyticsMetricsService_createAuditResultsFromXscAnalyticsBasicGeneralE }) } } + +func getDummyContentForGeneralEvent(withJas, withErr bool) *results.ScanCommandResults { + vulnerabilities := []services.Vulnerability{{IssueId: "XRAY-ID", Cves: []services.Cve{{Id: "CVE-123"}}, Components: map[string]services.Component{"issueId_2_direct_dependency": {}}}} + + cmdResults := results.NewCommandResults("", true) + scanResults := cmdResults.NewScanResults(results.ScanTarget{Target: "target"}) + scanResults.NewScaScanResults(&services.ScanResponse{Vulnerabilities: vulnerabilities}) + + if withJas { + scanResults.JasResults.ApplicabilityScanResults = []*sarif.Run{sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyPassingResult("applic_CVE-123"))} + scanResults.JasResults.SecretsScanResults = []*sarif.Run{ + sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("", 0, 0, 0, 0, ""))), + sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("", 1, 1, 1, 1, ""))), + } + scanResults.JasResults.IacScanResults = []*sarif.Run{ + sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("", 0, 0, 0, 0, ""))), + sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("", 1, 1, 1, 1, ""))), + } + scanResults.JasResults.SastScanResults = []*sarif.Run{ + sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("", 0, 0, 0, 0, ""))), + sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("", 1, 1, 1, 1, ""))), + } + } + + if withErr { + scanResults.Error = errors.New("an error") + } + + return cmdResults +} From 5fb51d90f2b77b2fb2f1df658255e2a8e8133953 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 2 Jul 2024 09:52:00 +0300 Subject: [PATCH 07/82] some changes --- commands/scan/scan.go | 33 ++++++++++++++++++++------------- utils/results/results.go | 22 +++++++++++++--------- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/commands/scan/scan.go b/commands/scan/scan.go index 3e58329e..e77bd7ca 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -18,6 +18,7 @@ import ( "github.com/jfrog/jfrog-cli-security/jas/runner" "github.com/jfrog/jfrog-cli-security/jas/secrets" "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/results/output" "github.com/jfrog/jfrog-cli-security/utils/severityutils" "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-cli-security/utils/xray" @@ -184,8 +185,8 @@ func (scanCmd *ScanCommand) indexFile(filePath string) (*xrayUtils.BinaryGraphNo } func (scanCmd *ScanCommand) Run() (err error) { - return scanCmd.RunAndRecordResults(func(scanResults *results.ScanCommandResults) error { - return utils.RecordSecurityCommandOutput(utils.ScanCommandSummaryResult{Results: scanResults.GetSummary(), Section: utils.Binary}) + return scanCmd.RunAndRecordResults(func(cmdResults *results.ScanCommandResults) error { + return output.RecordSecurityCommandOutput(output.Binary, cmdResults) }) } @@ -204,13 +205,17 @@ func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults * if err != nil { return err } + entitledForJas, err := jas.IsEntitledForJas(xrayManager, xrayVersion) + if err != nil { + return err + } + + cmdResults := results.NewCommandResults(xrayVersion, entitledForJas && scanCmd.commandSupportsJAS) - scanResults := results.NewAuditResults() - scanResults.XrayVersion = xrayVersion + - scanResults.ExtendedScanResults.EntitledForJas, err = jas.IsEntitledForJas(xrayManager, xrayVersion) errGroup := new(errgroup.Group) - if scanResults.ExtendedScanResults.EntitledForJas { + if cmdResults.EntitledForJas { // Download (if needed) the analyzer manager in a background routine. errGroup.Go(func() error { return jas.DownloadAnalyzerManagerIfNeeded(0) @@ -264,7 +269,7 @@ func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults * jasScanProducerErrors := make([][]formats.SimpleJsonError, threads) // Start walking on the filesystem to "produce" files that match the given pattern // while the consumer uses the indexer to index those files. - scanCmd.prepareScanTasks(fileProducerConsumer, indexedFileProducerConsumer, &JasScanProducerConsumer, scanResults.ExtendedScanResults.EntitledForJas, resultsArr, fileProducerErrors, indexedFileProducerErrors, jasScanProducerErrors, fileCollectingErrorsQueue, xrayVersion) + scanCmd.prepareScanTasks(fileProducerConsumer, indexedFileProducerConsumer, &JasScanProducerConsumer, cmdResults.EntitledForJas, resultsArr, fileProducerErrors, indexedFileProducerErrors, jasScanProducerErrors, fileCollectingErrorsQueue, xrayVersion) scanCmd.performScanTasks(fileProducerConsumer, indexedFileProducerConsumer, &JasScanProducerConsumer) // Handle results @@ -300,7 +305,7 @@ func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults * err = errors.New("failed while trying to get Analyzer Manager: " + err.Error()) } - if err = utils.NewResultsWriter(scanResults). + if err = utils.NewResultsWriter(cmdResults). SetOutputFormat(scanCmd.outputFormat). SetIncludeVulnerabilities(scanCmd.includeVulnerabilities). SetIncludeLicenses(scanCmd.includeLicenses). @@ -315,14 +320,14 @@ func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults * return err } - if err = recordResFunc(scanResults); err != nil { + if err = recordResFunc(cmdResults); err != nil { return err } // If includeVulnerabilities is false it means that context was provided, so we need to check for build violations. // If user provided --fail=false, don't fail the build. if scanCmd.fail && !scanCmd.includeVulnerabilities { - if utils.CheckIfFailBuild(scanResults.GetScaScansXrayResults()) { + if utils.CheckIfFailBuild(cmdResults.GetScaScansXrayResults()) { return utils.NewFailBuildError() } } @@ -341,14 +346,14 @@ func (scanCmd *ScanCommand) CommandName() string { return "xr_scan" } -func (scanCmd *ScanCommand) prepareScanTasks(fileProducer, indexedFileProducer parallel.Runner, jasFileProducerConsumer *utils.SecurityParallelRunner, entitledForJas bool, resultsArr [][]*ScanInfo, fileErrors, indexedFileErrors, jasErrors [][]formats.SimpleJsonError, fileCollectingErrorsQueue *clientutils.ErrorsQueue, xrayVersion string) { +func (scanCmd *ScanCommand) prepareScanTasks(fileProducer, indexedFileProducer parallel.Runner, jasFileProducerConsumer *utils.SecurityParallelRunner, cmdResults *results.ScanCommandResults, resultsArr [][]*ScanInfo, fileErrors, indexedFileErrors, jasErrors [][]formats.SimpleJsonError, fileCollectingErrorsQueue *clientutils.ErrorsQueue, xrayVersion string) { go func() { defer fileProducer.Done() // Iterate over file-spec groups and produce indexing tasks. // When encountering an error, log and move to next group. specFiles := scanCmd.spec.Files for i := range specFiles { - artifactHandlerFunc := scanCmd.createIndexerHandlerFunc(&specFiles[i], entitledForJas, indexedFileProducer, jasFileProducerConsumer, resultsArr, fileErrors, indexedFileErrors, jasErrors, xrayVersion) + artifactHandlerFunc := scanCmd.createIndexerHandlerFunc(&specFiles[i], cmdResults, indexedFileProducer, jasFileProducerConsumer, resultsArr, fileErrors, indexedFileErrors, jasErrors, xrayVersion) taskHandler := getAddTaskToProducerFunc(fileProducer, artifactHandlerFunc) err := collectFilesForIndexing(specFiles[i], taskHandler) @@ -360,7 +365,7 @@ func (scanCmd *ScanCommand) prepareScanTasks(fileProducer, indexedFileProducer p }() } -func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, entitledForJas bool, indexedFileProducer parallel.Runner, jasFileProducerConsumer *utils.SecurityParallelRunner, resultsArr [][]*ScanInfo, fileErrors, indexedFileErrors, jasErrors [][]formats.SimpleJsonError, xrayVersion string) FileContext { +func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, cmdResults *results.ScanCommandResults, indexedFileProducer parallel.Runner, jasFileProducerConsumer *utils.SecurityParallelRunner, resultsArr [][]*ScanInfo, fileErrors, indexedFileErrors, jasErrors [][]formats.SimpleJsonError, xrayVersion string) FileContext { return func(filePath string) parallel.TaskFunc { return func(threadId int) (err error) { logMsgPrefix := clientutils.GetLogMsgPrefix(threadId, false) @@ -368,6 +373,8 @@ func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, entitledFo if scanCmd.progress != nil { scanCmd.progress.SetHeadlineMsg("Indexing file: " + filepath.Base(filePath) + " 🗄") } + // Create a scan target for the file. + targetResults := cmdResults.NewScanResults(results.ScanTarget{Target: filePath, Name: filepath.Base(filePath)}) graph, err := scanCmd.indexFile(filePath) if err != nil { fileErrors[threadId] = append(fileErrors[threadId], formats.SimpleJsonError{FilePath: filePath, ErrorMessage: err.Error()}) diff --git a/utils/results/results.go b/utils/results/results.go index ed884a30..41e42fd6 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -2,6 +2,7 @@ package results import ( "errors" + "sync" "github.com/jfrog/gofrog/datastructures" "github.com/jfrog/jfrog-cli-security/utils/jasutils" @@ -14,11 +15,13 @@ import ( type ScanCommandResults struct { // General fields describing the command metadata XrayVersion string `json:"xray_version"` - EntitledForJas bool `json:"entitledForJas"` + EntitledForJas bool `json:"jas_entitled"` // MultiScanId is a unique identifier that is used to group multiple scans together. MultiScanId string `json:"multi_scan_id,omitempty"` // Results for each target in the command Scans []*ScanResults `json:"scans"` + scansMutex sync.Mutex `json:"-"` + // Error that occurred during the command execution Errors error `json:"errors,omitempty"` } @@ -41,21 +44,20 @@ type ScanResults struct { } type ScaScanResults struct { - // Related Descriptor that provided the dependencies for the scan - ScanTarget + Descriptors []string `json:"descriptors,omitempty"` // Sca scan results - XrayResult services.ScanResponse `json:"XrayScan"` + XrayResult services.ScanResponse `json:"xray_scan"` } type JasScansResults struct { - ApplicabilityScanResults []*sarif.Run `json:"ContextualAnalysis,omitempty"` - SecretsScanResults []*sarif.Run `json:"Secrets,omitempty"` - IacScanResults []*sarif.Run `json:"Iac,omitempty"` - SastScanResults []*sarif.Run `json:"Sast,omitempty"` + ApplicabilityScanResults []*sarif.Run `json:"contextual_analysis,omitempty"` + SecretsScanResults []*sarif.Run `json:"secrets,omitempty"` + IacScanResults []*sarif.Run `json:"iac,omitempty"` + SastScanResults []*sarif.Run `json:"sast,omitempty"` } func NewCommandResults(xrayVersion string, entitledForJas bool) *ScanCommandResults { - return &ScanCommandResults{XrayVersion: xrayVersion, EntitledForJas: entitledForJas} + return &ScanCommandResults{XrayVersion: xrayVersion, EntitledForJas: entitledForJas, scansMutex: sync.Mutex{}} } func (r *ScanCommandResults) SetMultiScanId(multiScanId string) *ScanCommandResults { @@ -151,7 +153,9 @@ func (r *ScanCommandResults) NewScanResults(target ScanTarget) *ScanResults { if r.EntitledForJas { scanResults.JasResults = &JasScansResults{} } + r.scansMutex.Lock() r.Scans = append(r.Scans, scanResults) + r.scansMutex.Unlock() return scanResults } From adb3de1e8319cdc01fccdbc2d08dce3c38d6eacc Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 2 Jul 2024 19:34:53 +0300 Subject: [PATCH 08/82] continue implement --- commands/audit/audit.go | 78 ++++- commands/audit/audit_test.go | 161 ++++++++++ commands/audit/scarunner.go | 115 +++---- commands/audit/scarunner_test.go | 108 ------- commands/scan/dockerscan.go | 13 +- commands/scan/scan.go | 154 ++++----- .../applicabilitymanager_test.go | 8 +- jas/common.go | 21 +- jas/iac/iacscanner_test.go | 18 +- jas/runner/jasrunner.go | 65 ++-- jas/runner/jasrunner_test.go | 12 +- jas/sast/sastscanner_test.go | 16 +- jas/secrets/secretsscanner_test.go | 14 +- utils/results/common.go | 4 +- utils/results/conversion/convertor.go | 12 +- utils/results/output/resultwriter.go | 292 +++++++++++++++++- utils/results/output/securityJobSummary.go | 4 +- utils/results/results.go | 102 +++--- utils/results/results_test.go | 14 +- utils/resultwriter.go | 14 +- utils/xsc/analyticsmetrics.go | 2 +- utils/xsc/analyticsmetrics_test.go | 8 +- 22 files changed, 828 insertions(+), 407 deletions(-) create mode 100644 commands/audit/audit_test.go diff --git a/commands/audit/audit.go b/commands/audit/audit.go index 55692067..ae08a246 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -8,10 +8,12 @@ import ( jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-cli-security/commands/audit/sca" "github.com/jfrog/jfrog-cli-security/jas/applicability" "github.com/jfrog/jfrog-cli-security/jas/runner" "github.com/jfrog/jfrog-cli-security/jas/secrets" "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-cli-security/utils/xray/scangraph" "github.com/jfrog/jfrog-cli-security/utils/xsc" @@ -20,6 +22,7 @@ import ( xrayutils "github.com/jfrog/jfrog-cli-security/utils/xray" clientutils "github.com/jfrog/jfrog-client-go/utils" + "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "github.com/jfrog/jfrog-client-go/utils/log" "github.com/jfrog/jfrog-client-go/xray" "github.com/jfrog/jfrog-client-go/xray/services" @@ -180,7 +183,7 @@ func (auditCmd *AuditCommand) CommandName() string { // Runs an audit scan based on the provided auditParams. // Returns an audit Results object containing all the scan results. // If the current server is entitled for JAS, the advanced security results will be included in the scan results. -func RunAudit(auditParams *AuditParams) (cmdResults *results.ScanCommandResults, err error) { +func RunAudit(auditParams *AuditParams) (cmdResults *results.SecurityCommandResults, err error) { // Prepare serverDetails, err := auditParams.ServerDetails() if err != nil { @@ -198,14 +201,15 @@ func RunAudit(auditParams *AuditParams) (cmdResults *results.ScanCommandResults, return } // Initialize Results struct - cmdResults = results.NewCommandResults(auditParams.xrayVersion, entitledForJas).SetMultiScanId(auditParams.commonGraphScanParams.MultiScanId) - - auditParallelRunner := utils.CreateSecurityParallelRunner(auditParams.threads) - auditParallelRunner.ErrWg.Add(1) + cmdResults = initCmdResults(entitledForJas, auditParams) jfrogAppsConfig, err := jas.CreateJFrogAppsConfig(auditParams.workingDirs) if err != nil { return cmdResults, fmt.Errorf("failed to create JFrogAppsConfig: %s", err.Error()) } + // Initialize the parallel runner + auditParallelRunner := utils.CreateSecurityParallelRunner(auditParams.threads) + auditParallelRunner.ErrWg.Add(1) + // Add the JAS scans to the parallel runner jasScanner := &jas.JasScanner{} if cmdResults.EntitledForJas { // Download (if needed) the analyzer manager and run scanners. @@ -238,9 +242,8 @@ func RunAudit(auditParams *AuditParams) (cmdResults *results.ScanCommandResults, // a new routine that collects errors from the err channel into results object go func() { defer auditParallelRunner.ErrWg.Done() - // TODO: assign error to correct scan for e := range auditParallelRunner.ErrorsQueue { - cmdResults.Errors = errors.Join(cmdResults.Errors, e) + cmdResults.Error = errors.Join(cmdResults.Error, e) } }() auditParallelRunner.Runner.Run() @@ -256,7 +259,7 @@ func isEntitledForJas(xrayManager *xray.XrayServicesManager, auditParams *AuditP return jas.IsEntitledForJas(xrayManager, auditParams.xrayVersion) } -func downloadAnalyzerManagerAndRunScanners(auditParallelRunner *utils.SecurityParallelRunner, scanResults *results.ScanCommandResults, +func downloadAnalyzerManagerAndRunScanners(auditParallelRunner *utils.SecurityParallelRunner, scanResults *results.SecurityCommandResults, serverDetails *config.ServerDetails, auditParams *AuditParams, scanner *jas.JasScanner, jfrogAppsConfig *jfrogappsconfig.JFrogAppsConfig, threadId int) (err error) { defer func() { auditParallelRunner.JasWg.Done() @@ -264,12 +267,65 @@ func downloadAnalyzerManagerAndRunScanners(auditParallelRunner *utils.SecurityPa if err = jas.DownloadAnalyzerManagerIfNeeded(threadId); err != nil { return fmt.Errorf("%s failed to download analyzer manager: %s", clientutils.GetLogMsgPrefix(threadId, false), err.Error()) } - scanner, err = jas.CreateJasScanner(scanner, jfrogAppsConfig, serverDetails, auditParams.Exclusions()...) + scanner, err = jas.CreateJasScanner(scanner, serverDetails, auditParams.Exclusions()...) if err != nil { return fmt.Errorf("failed to create jas scanner: %s", err.Error()) } - if err = runner.AddJasScannersTasks(auditParallelRunner, scanResults, scanResults.GetTechnologies(), auditParams.DirectDependencies(), serverDetails, auditParams.thirdPartyApplicabilityScan, auditParams.commonGraphScanParams.MultiScanId, scanner, applicability.ApplicabilityScannerType, secrets.SecretsScannerType, auditParallelRunner.AddErrorToChan, auditParams.ScansToPerform()); err != nil { - return fmt.Errorf("%s failed to run JAS scanners: %s", clientutils.GetLogMsgPrefix(threadId, false), err.Error()) + // Run JAS scanners for each scan target + for _, scan := range scanResults.Targets { + module := jas.GetModule(scan.Target, jfrogAppsConfig) + if module == nil { + scan.AddError(fmt.Errorf("Can't find module for path %s", scan.Target)) + continue + } + if err = runner.AddJasScannersTasks(auditParallelRunner, *module, scan, scan.GetTechnologies(), auditParams.DirectDependencies(), serverDetails, auditParams.thirdPartyApplicabilityScan, auditParams.commonGraphScanParams.MultiScanId, scanner, applicability.ApplicabilityScannerType, secrets.SecretsScannerType, auditParams.ScansToPerform()); err != nil { + return fmt.Errorf("%s failed to run JAS scanners: %s", clientutils.GetLogMsgPrefix(threadId, false), err.Error()) + } + } + return +} + +func initCmdResults(entitledForJas bool, params *AuditParams) (cmdResults *results.SecurityCommandResults) { + cmdResults = results.NewCommandResults(params.xrayVersion, entitledForJas).SetMultiScanId(params.commonGraphScanParams.MultiScanId) + detectScanTargets(cmdResults, params) + scanInfo, err := coreutils.GetJsonIndent(cmdResults) + if err != nil { + return + } + log.Info(fmt.Sprintf("Preforming %d scans:\n%s", len(cmdResults.Targets), scanInfo)) + return +} + +func detectScanTargets(cmdResults *results.SecurityCommandResults, params *AuditParams) { + for _, requestedDirectory := range params.workingDirs { + if !fileutils.IsPathExists(requestedDirectory, false) { + log.Warn("The working directory", requestedDirectory, "doesn't exist. Skipping SCA scan...") + continue + } + // Detect descriptors and technologies in the requested directory. + techToWorkingDirs, err := techutils.DetectTechnologiesDescriptors(requestedDirectory, params.IsRecursiveScan(), params.Technologies(), getRequestedDescriptors(params), sca.GetExcludePattern(params.AuditBasicParams)) + if err != nil { + log.Warn("Couldn't detect technologies in", requestedDirectory, "directory.", err.Error()) + continue + } + // Create scans to preform + for tech, workingDirs := range techToWorkingDirs { + if tech == techutils.Dotnet { + // We detect Dotnet and Nuget the same way, if one detected so does the other. + // We don't need to scan for both and get duplicate results. + continue + } + if len(workingDirs) == 0 { + // Requested technology (from params) descriptors/indicators was not found, scan only requested directory for this technology. + cmdResults.NewScanResults(results.ScanTarget{Target: requestedDirectory, Technology: tech}) + // scansToPreform = append(scansToPreform, &results.ScanTarget{Target: requestedDirectory, Technology: tech}) + } + for workingDir, descriptors := range workingDirs { + // Add scan for each detected working directory. + cmdResults.NewScanResults(results.ScanTarget{Target: workingDir, Technology: tech}).SetDescriptors(descriptors...) + // scansToPreform = append(scansToPreform, &results.ScanTarget{Target: workingDir, Technology: tech, Descriptors: descriptors}) + } + } } return } diff --git a/commands/audit/audit_test.go b/commands/audit/audit_test.go new file mode 100644 index 00000000..8680b1e7 --- /dev/null +++ b/commands/audit/audit_test.go @@ -0,0 +1,161 @@ +package audit + +import ( + "path/filepath" + "sort" + "testing" + + "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/techutils" + "github.com/stretchr/testify/assert" +) + + +func TestDetectScansToPreform(t *testing.T) { + + dir, cleanUp := createTestDir(t) + + tests := []struct { + name string + wd string + params func() *AuditParams + expected []*results.TargetResults + }{ + { + name: "Test specific technologies", + wd: dir, + params: func() *AuditParams { + param := NewAuditParams().SetWorkingDirs([]string{dir}) + param.SetTechnologies([]string{"maven", "npm", "go"}).SetIsRecursiveScan(true) + return param + }, + expected: []*results.TargetResults{ + { + ScanTarget: results.ScanTarget{ + Technology: techutils.Maven, + Target: filepath.Join(dir, "dir", "maven"), + }, + ScaResults: &results.ScaScanResults{ + Descriptors: []string{ + filepath.Join(dir, "dir", "maven", "pom.xml"), + filepath.Join(dir, "dir", "maven", "maven-sub", "pom.xml"), + filepath.Join(dir, "dir", "maven", "maven-sub2", "pom.xml"), + }, + }, + }, + { + ScanTarget: results.ScanTarget{ + Technology: techutils.Npm, + Target: filepath.Join(dir, "dir", "npm"), + }, + ScaResults: &results.ScaScanResults{ + Descriptors: []string{filepath.Join(dir, "dir", "npm", "package.json")}, + }, + }, + { + ScanTarget: results.ScanTarget{ + Technology: techutils.Go, + Target: filepath.Join(dir, "dir", "go"), + }, + ScaResults: &results.ScaScanResults{ + Descriptors: []string{filepath.Join(dir, "dir", "go", "go.mod")}, + }, + }, + }, + }, + { + name: "Test all", + wd: dir, + params: func() *AuditParams { + param := NewAuditParams().SetWorkingDirs([]string{dir}) + param.SetIsRecursiveScan(true) + return param + }, + expected: []*results.TargetResults{ + { + ScanTarget: results.ScanTarget{ + Technology: techutils.Maven, + Target: filepath.Join(dir, "dir", "maven"), + }, + ScaResults: &results.ScaScanResults{ + Descriptors: []string{ + filepath.Join(dir, "dir", "maven", "pom.xml"), + filepath.Join(dir, "dir", "maven", "maven-sub", "pom.xml"), + filepath.Join(dir, "dir", "maven", "maven-sub2", "pom.xml"), + }, + }, + }, + { + ScanTarget: results.ScanTarget{ + Technology: techutils.Npm, + Target: filepath.Join(dir, "dir", "npm"), + }, + ScaResults: &results.ScaScanResults{ + Descriptors: []string{filepath.Join(dir, "dir", "npm", "package.json")}, + }, + }, + { + ScanTarget: results.ScanTarget{ + Technology: techutils.Go, + Target: filepath.Join(dir, "dir", "go"), + }, + ScaResults: &results.ScaScanResults{ + Descriptors: []string{filepath.Join(dir, "dir", "go", "go.mod")}, + }, + }, + { + ScanTarget: results.ScanTarget{ + Technology: techutils.Yarn, + Target: filepath.Join(dir, "yarn"), + }, + ScaResults: &results.ScaScanResults{ + Descriptors: []string{filepath.Join(dir, "yarn", "package.json")}, + }, + }, + { + ScanTarget: results.ScanTarget{ + Technology: techutils.Pip, + Target: filepath.Join(dir, "yarn", "Pip"), + }, + ScaResults: &results.ScaScanResults{ + Descriptors: []string{filepath.Join(dir, "yarn", "Pip", "requirements.txt")}, + }, + }, + { + ScanTarget: results.ScanTarget{ + Technology: techutils.Pipenv, + Target: filepath.Join(dir, "yarn", "Pipenv"), + }, + ScaResults: &results.ScaScanResults{ + Descriptors: []string{filepath.Join(dir, "yarn", "Pipenv", "Pipfile")}, + }, + }, + { + ScanTarget: results.ScanTarget{ + Technology: techutils.Nuget, + Target: filepath.Join(dir, "Nuget"), + }, + ScaResults: &results.ScaScanResults{ + Descriptors: []string{filepath.Join(dir, "Nuget", "project.sln"), filepath.Join(dir, "Nuget", "Nuget-sub", "project.csproj")}, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + results := results.NewCommandResults("", true) + detectScanTargets(results, test.params()) + if assert.Len(t, results.Targets, len(test.expected)) { + for i := range results.Targets { + sort.Strings(results.Targets[i].ScaResults.Descriptors) + sort.Strings(test.expected[i].ScaResults.Descriptors) + } + } + assert.ElementsMatch(t, test.expected, results.Targets) + }) + } + + cleanUp() +} \ No newline at end of file diff --git a/commands/audit/scarunner.go b/commands/audit/scarunner.go index 06002224..00dfdd57 100644 --- a/commands/audit/scarunner.go +++ b/commands/audit/scarunner.go @@ -16,7 +16,6 @@ import ( "github.com/jfrog/gofrog/parallel" "github.com/jfrog/jfrog-cli-core/v2/common/project" "github.com/jfrog/jfrog-cli-core/v2/utils/config" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-security/commands/audit/sca" _go "github.com/jfrog/jfrog-cli-security/commands/audit/sca/go" "github.com/jfrog/jfrog-cli-security/commands/audit/sca/java" @@ -38,7 +37,19 @@ import ( xrayCmdUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" ) -func buildDepTreeAndRunScaScan(auditParallelRunner *utils.SecurityParallelRunner, auditParams *AuditParams, cmdResults *results.ScanCommandResults) (err error) { +func shouldPreformScaScan(cmdResults *results.SecurityCommandResults) bool { + if len(cmdResults.Targets) == 0 { + return false + } + for _, scan := range cmdResults.Targets { + if scan.Technology != "" { + return true + } + } + return false +} + +func buildDepTreeAndRunScaScan(auditParallelRunner *utils.SecurityParallelRunner, auditParams *AuditParams, cmdResults *results.SecurityCommandResults) (err error) { if len(auditParams.ScansToPerform()) > 0 && !slices.Contains(auditParams.ScansToPerform(), xrayutils.ScaScan) { log.Debug("Skipping SCA scan as requested by input...") return @@ -52,80 +63,70 @@ func buildDepTreeAndRunScaScan(auditParallelRunner *utils.SecurityParallelRunner if err != nil { return } - - scans := getScaScansToPreform(auditParams) - if len(scans) == 0 { + if !shouldPreformScaScan(cmdResults) { log.Info("Couldn't determine a package manager or build tool used by this project. Skipping the SCA scan...") return } - scanInfo, err := coreutils.GetJsonIndent(scans) - if err != nil { - return - } - log.Info(fmt.Sprintf("Preforming %d SCA scans:\n%s", len(scans), scanInfo)) - defer func() { // Make sure to return to the original working directory, buildDependencyTree may change it err = errors.Join(err, os.Chdir(currentWorkingDir)) }() - for _, scan := range scans { - // Create sub scan - cmdResults.NewScanResults(results.ScanTarget{Target: scan}) - + // Preform SCA scans + for _, scan := range cmdResults.Targets { + if scan.Technology == "" { + log.Warn(fmt.Sprintf("Couldn't determine a package manager or build tool used by this project. Skipping the SCA scan in '%s'...", scan.Target)) + continue + } // Get the dependency tree for the technology in the working directory. treeResult, bdtErr := buildDependencyTree(scan, auditParams) if bdtErr != nil { - err = errors.Join(err, fmt.Errorf("audit command in '%s' failed:\n%s", scan.Target, bdtErr.Error())) + err = errors.Join(err, fmt.Errorf("failed to get dependencies trees in '%s':\n%s", scan.Target, bdtErr.Error())) continue } // Create sca scan task auditParallelRunner.ScaScansWg.Add(1) _, taskErr := auditParallelRunner.Runner.AddTaskWithError(executeScaScanTask(auditParallelRunner, serverDetails, auditParams, scan, treeResult), func(err error) { - auditParallelRunner.AddErrorToChan(fmt.Errorf("audit command in '%s' failed:\n%s", scan.Target, err.Error())) + auditParallelRunner.AddErrorToChan(fmt.Errorf("SCA scan failed in '%s':\n%s", scan.Target, err.Error())) }) if taskErr != nil { return fmt.Errorf("failed to create sca scan task for '%s': %s", scan.Target, taskErr.Error()) } - // Add the scan to the results - auditParallelRunner.ResultsMu.Lock() - cmdResults.ScaResults = append(cmdResults.ScaResults, scan) - auditParallelRunner.ResultsMu.Unlock() } return } -// Calculate the scans to preform -func getScaScansToPreform(params *AuditParams) (scansToPreform []*results.ScanTarget) { - for _, requestedDirectory := range params.workingDirs { - if !fileutils.IsPathExists(requestedDirectory, false) { - log.Warn("The working directory", requestedDirectory, "doesn't exist. Skipping SCA scan...") - continue - } - // Detect descriptors and technologies in the requested directory. - techToWorkingDirs, err := techutils.DetectTechnologiesDescriptors(requestedDirectory, params.IsRecursiveScan(), params.Technologies(), getRequestedDescriptors(params), sca.GetExcludePattern(params.AuditBasicParams)) - if err != nil { - log.Warn("Couldn't detect technologies in", requestedDirectory, "directory.", err.Error()) - continue - } - // Create scans to preform - for tech, workingDirs := range techToWorkingDirs { - if tech == techutils.Dotnet { - // We detect Dotnet and Nuget the same way, if one detected so does the other. - // We don't need to scan for both and get duplicate results. - continue - } - if len(workingDirs) == 0 { - // Requested technology (from params) descriptors/indicators was not found, scan only requested directory for this technology. - scansToPreform = append(scansToPreform, &results.ScanTarget{Target: requestedDirectory, Technology: tech}) - } - for workingDir, descriptors := range workingDirs { - // Add scan for each detected working directory. - scansToPreform = append(scansToPreform, &results.ScanTarget{Target: workingDir, Technology: tech, Descriptors: descriptors}) - } - } - } - return -} +// // Calculate the scans to preform +// func getScaScansToPreform(params *AuditParams) (scansToPreform []*results.ScanTarget) { +// for _, requestedDirectory := range params.workingDirs { +// if !fileutils.IsPathExists(requestedDirectory, false) { +// log.Warn("The working directory", requestedDirectory, "doesn't exist. Skipping SCA scan...") +// continue +// } +// // Detect descriptors and technologies in the requested directory. +// techToWorkingDirs, err := techutils.DetectTechnologiesDescriptors(requestedDirectory, params.IsRecursiveScan(), params.Technologies(), getRequestedDescriptors(params), sca.GetExcludePattern(params.AuditBasicParams)) +// if err != nil { +// log.Warn("Couldn't detect technologies in", requestedDirectory, "directory.", err.Error()) +// continue +// } +// // Create scans to preform +// for tech, workingDirs := range techToWorkingDirs { +// if tech == techutils.Dotnet { +// // We detect Dotnet and Nuget the same way, if one detected so does the other. +// // We don't need to scan for both and get duplicate results. +// continue +// } +// if len(workingDirs) == 0 { +// // Requested technology (from params) descriptors/indicators was not found, scan only requested directory for this technology. +// scansToPreform = append(scansToPreform, &results.ScanTarget{Target: requestedDirectory, Technology: tech}) +// } +// for workingDir, descriptors := range workingDirs { +// // Add scan for each detected working directory. +// scansToPreform = append(scansToPreform, &results.ScanTarget{Target: workingDir, Technology: tech, Descriptors: descriptors}) +// } +// } +// } +// return +// } func getRequestedDescriptors(params *AuditParams) map[techutils.Technology][]string { requestedDescriptors := map[techutils.Technology][]string{} @@ -137,7 +138,7 @@ func getRequestedDescriptors(params *AuditParams) map[techutils.Technology][]str // Preform the SCA scan for the given scan information. func executeScaScanTask(auditParallelRunner *utils.SecurityParallelRunner, serverDetails *config.ServerDetails, auditParams *AuditParams, - scan *results.ScaScanResult, treeResult *DependencyTreeResult) parallel.TaskFunc { + scan *results.TargetResults, treeResult *DependencyTreeResult) parallel.TaskFunc { return func(threadId int) (err error) { log.Info(clientutils.GetLogMsgPrefix(threadId, false)+"Running SCA scan for", scan.Target, "vulnerable dependencies in", scan.Target, "directory...") defer func() { @@ -148,10 +149,10 @@ func executeScaScanTask(auditParallelRunner *utils.SecurityParallelRunner, serve if xrayErr != nil { return fmt.Errorf("%s Xray dependency tree scan request on '%s' failed:\n%s", clientutils.GetLogMsgPrefix(threadId, false), scan.Technology, xrayErr.Error()) } - scan.IsMultipleRootProject = clientutils.Pointer(len(treeResult.FullDepTrees) > 1) + scan.ScaResults.IsMultipleRootProject = clientutils.Pointer(len(treeResult.FullDepTrees) > 1) addThirdPartyDependenciesToParams(auditParams, scan.Technology, treeResult.FlatTree, treeResult.FullDepTrees) auditParallelRunner.ResultsMu.Lock() - scan.XrayResults = append(scan.XrayResults, scanResults...) + scan.ScaResults.XrayResults = append(scan.ScaResults.XrayResults, scanResults...) auditParallelRunner.ResultsMu.Unlock() return } @@ -415,7 +416,7 @@ func logDeps(uniqueDeps any) (err error) { } // This method will change the working directory to the scan's working directory. -func buildDependencyTree(scan *results.ScaScanResult, params *AuditParams) (*DependencyTreeResult, error) { +func buildDependencyTree(scan *results.TargetResults, params *AuditParams) (*DependencyTreeResult, error) { if err := os.Chdir(scan.Target); err != nil { return nil, errorutils.CheckError(err) } diff --git a/commands/audit/scarunner_test.go b/commands/audit/scarunner_test.go index fb3f52af..0dda7c36 100644 --- a/commands/audit/scarunner_test.go +++ b/commands/audit/scarunner_test.go @@ -3,11 +3,8 @@ package audit import ( "os" "path/filepath" - "sort" "testing" - "github.com/jfrog/jfrog-cli-security/utils/results" - "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" @@ -117,108 +114,3 @@ func createEmptyFile(t *testing.T, path string) { assert.NoError(t, file.Close()) } -func TestGetScaScansToPreform(t *testing.T) { - - dir, cleanUp := createTestDir(t) - - tests := []struct { - name string - wd string - params func() *AuditParams - expected []*results.ScaScanResult - }{ - { - name: "Test specific technologies", - wd: dir, - params: func() *AuditParams { - param := NewAuditParams().SetWorkingDirs([]string{dir}) - param.SetTechnologies([]string{"maven", "npm", "go"}).SetIsRecursiveScan(true) - return param - }, - expected: []*results.ScaScanResult{ - { - Technology: techutils.Maven, - Target: filepath.Join(dir, "dir", "maven"), - Descriptors: []string{ - filepath.Join(dir, "dir", "maven", "pom.xml"), - filepath.Join(dir, "dir", "maven", "maven-sub", "pom.xml"), - filepath.Join(dir, "dir", "maven", "maven-sub2", "pom.xml"), - }, - }, - { - Technology: techutils.Npm, - Target: filepath.Join(dir, "dir", "npm"), - Descriptors: []string{filepath.Join(dir, "dir", "npm", "package.json")}, - }, - { - Technology: techutils.Go, - Target: filepath.Join(dir, "dir", "go"), - Descriptors: []string{filepath.Join(dir, "dir", "go", "go.mod")}, - }, - }, - }, - { - name: "Test all", - wd: dir, - params: func() *AuditParams { - param := NewAuditParams().SetWorkingDirs([]string{dir}) - param.SetIsRecursiveScan(true) - return param - }, - expected: []*results.ScaScanResult{ - { - Technology: techutils.Maven, - Target: filepath.Join(dir, "dir", "maven"), - Descriptors: []string{ - filepath.Join(dir, "dir", "maven", "pom.xml"), - filepath.Join(dir, "dir", "maven", "maven-sub", "pom.xml"), - filepath.Join(dir, "dir", "maven", "maven-sub2", "pom.xml"), - }, - }, - { - Technology: techutils.Npm, - Target: filepath.Join(dir, "dir", "npm"), - Descriptors: []string{filepath.Join(dir, "dir", "npm", "package.json")}, - }, - { - Technology: techutils.Go, - Target: filepath.Join(dir, "dir", "go"), - Descriptors: []string{filepath.Join(dir, "dir", "go", "go.mod")}, - }, - { - Technology: techutils.Yarn, - Target: filepath.Join(dir, "yarn"), - Descriptors: []string{filepath.Join(dir, "yarn", "package.json")}, - }, - { - Technology: techutils.Pip, - Target: filepath.Join(dir, "yarn", "Pip"), - Descriptors: []string{filepath.Join(dir, "yarn", "Pip", "requirements.txt")}, - }, - { - Technology: techutils.Pipenv, - Target: filepath.Join(dir, "yarn", "Pipenv"), - Descriptors: []string{filepath.Join(dir, "yarn", "Pipenv", "Pipfile")}, - }, - { - Technology: techutils.Nuget, - Target: filepath.Join(dir, "Nuget"), - Descriptors: []string{filepath.Join(dir, "Nuget", "project.sln"), filepath.Join(dir, "Nuget", "Nuget-sub", "project.csproj")}, - }, - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - result := getScaScansToPreform(test.params()) - for i := range result { - sort.Strings(result[i].Descriptors) - sort.Strings(test.expected[i].Descriptors) - } - assert.ElementsMatch(t, test.expected, result) - }) - } - - cleanUp() -} diff --git a/commands/scan/dockerscan.go b/commands/scan/dockerscan.go index 26f9a45d..ad0930b5 100644 --- a/commands/scan/dockerscan.go +++ b/commands/scan/dockerscan.go @@ -9,8 +9,8 @@ import ( "strings" "github.com/jfrog/jfrog-cli-core/v2/common/spec" - "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/results/output" "github.com/jfrog/jfrog-cli-security/utils/xray" clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/errorutils" @@ -95,15 +95,16 @@ func (dsc *DockerScanCommand) Run() (err error) { err = errorutils.CheckError(e) } }() - return dsc.ScanCommand.RunAndRecordResults(func(scanResults *results.ScanCommandResults) (err error) { - if scanResults == nil || len(scanResults.ScaResults) == 0 { + return dsc.ScanCommand.RunAndRecordResults(func(cmdResults *results.SecurityCommandResults) (err error) { + if cmdResults == nil || len(cmdResults.Targets) == 0 { return } - for i := range scanResults.ScaResults { + for i := range cmdResults.Targets { // Set the image tag as the target for the scan results (will show `image.tar` as target if not set) - scanResults.ScaResults[i].Target = dsc.imageTag + cmdResults.Targets[i].Name = dsc.imageTag + // scanResults.Scans[i].Target = dsc.imageTag } - return utils.RecordSecurityCommandOutput(utils.ScanCommandSummaryResult{Results: scanResults.GetSummary(), Section: utils.Binary}) + return output.RecordSecurityCommandOutput(output.Binary, cmdResults) }) } diff --git a/commands/scan/scan.go b/commands/scan/scan.go index e77bd7ca..b827ecfe 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -13,6 +13,7 @@ import ( "golang.org/x/exp/maps" "golang.org/x/exp/slices" + jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" "github.com/jfrog/jfrog-cli-security/jas" "github.com/jfrog/jfrog-cli-security/jas/applicability" "github.com/jfrog/jfrog-cli-security/jas/runner" @@ -45,12 +46,6 @@ import ( type FileContext func(string) parallel.TaskFunc type indexFileHandlerFunc func(file string) -type ScanInfo struct { - Target string - Result *services.ScanResponse - ExtendedScanResults *results.ExtendedScanResults -} - const ( BypassArchiveLimitsMinXrayVersion = "3.59.0" indexingCommand = "graph" @@ -185,12 +180,12 @@ func (scanCmd *ScanCommand) indexFile(filePath string) (*xrayUtils.BinaryGraphNo } func (scanCmd *ScanCommand) Run() (err error) { - return scanCmd.RunAndRecordResults(func(cmdResults *results.ScanCommandResults) error { + return scanCmd.RunAndRecordResults(func(cmdResults *results.SecurityCommandResults) error { return output.RecordSecurityCommandOutput(output.Binary, cmdResults) }) } -func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults *results.ScanCommandResults) error) (err error) { +func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults *results.SecurityCommandResults) error) (err error) { defer func() { if err != nil { var e *exec.ExitError @@ -209,10 +204,8 @@ func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults * if err != nil { return err } - - cmdResults := results.NewCommandResults(xrayVersion, entitledForJas && scanCmd.commandSupportsJAS) - + cmdResults := results.NewCommandResults(xrayVersion, entitledForJas && scanCmd.commandSupportsJAS) errGroup := new(errgroup.Group) if cmdResults.EntitledForJas { @@ -257,48 +250,28 @@ func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults * threads = scanCmd.threads } - // resultsArr is a two-dimensional array. Each array in it contains a list of ScanResponses that were requested and collected by a specific thread. - resultsArr := make([][]*ScanInfo, threads) - fileProducerConsumer := parallel.NewRunner(scanCmd.threads, 20000, false) - fileProducerErrors := make([][]formats.SimpleJsonError, threads) - indexedFileProducerConsumer := parallel.NewRunner(scanCmd.threads, 20000, false) - indexedFileProducerErrors := make([][]formats.SimpleJsonError, threads) + fileProducerConsumer := parallel.NewRunner(threads, 20000, false) + indexedFileProducerConsumer := parallel.NewRunner(threads, 20000, false) fileCollectingErrorsQueue := clientutils.NewErrorsQueue(1) // Parallel security runner for JAS scans - JasScanProducerConsumer := utils.NewSecurityParallelRunner(scanCmd.threads) - jasScanProducerErrors := make([][]formats.SimpleJsonError, threads) + JasScanProducerConsumer := utils.NewSecurityParallelRunner(threads) + // Start walking on the filesystem to "produce" files that match the given pattern // while the consumer uses the indexer to index those files. - scanCmd.prepareScanTasks(fileProducerConsumer, indexedFileProducerConsumer, &JasScanProducerConsumer, cmdResults.EntitledForJas, resultsArr, fileProducerErrors, indexedFileProducerErrors, jasScanProducerErrors, fileCollectingErrorsQueue, xrayVersion) + scanCmd.prepareScanTasks(fileProducerConsumer, indexedFileProducerConsumer, &JasScanProducerConsumer, cmdResults, fileCollectingErrorsQueue) scanCmd.performScanTasks(fileProducerConsumer, indexedFileProducerConsumer, &JasScanProducerConsumer) // Handle results - flatResults := []*results.ScaScanResult{} - - for _, arr := range resultsArr { - for _, res := range arr { - flatResults = append(flatResults, &results.ScaScanResult{Target: res.Target, XrayResults: []services.ScanResponse{*res.Result}}) - scanResults.ExtendedScanResults.ApplicabilityScanResults = append(scanResults.ExtendedScanResults.ApplicabilityScanResults, res.ExtendedScanResults.ApplicabilityScanResults...) - scanResults.ExtendedScanResults.SecretsScanResults = append(scanResults.ExtendedScanResults.SecretsScanResults, res.ExtendedScanResults.SecretsScanResults...) - } - } if scanCmd.progress != nil { if err = scanCmd.progress.Quit(); err != nil { return err } - } fileCollectingErr := fileCollectingErrorsQueue.GetError() - var scanErrors []formats.SimpleJsonError if fileCollectingErr != nil { - scanErrors = append(scanErrors, formats.SimpleJsonError{ErrorMessage: fileCollectingErr.Error()}) + cmdResults.Error = errors.Join(cmdResults.Error, fileCollectingErr) } - scanErrors = appendErrorSlice(scanErrors, fileProducerErrors) - scanErrors = appendErrorSlice(scanErrors, indexedFileProducerErrors) - scanErrors = appendErrorSlice(scanErrors, jasScanProducerErrors) - - scanResults.ScaResults = flatResults // Wait for the Download of the AnalyzerManager to complete. if err = errGroup.Wait(); err != nil { @@ -316,10 +289,6 @@ func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults * return } - if err != nil { - return err - } - if err = recordResFunc(cmdResults); err != nil { return err } @@ -331,8 +300,8 @@ func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults * return utils.NewFailBuildError() } } - if len(scanErrors) > 0 { - return errorutils.CheckErrorf(scanErrors[0].ErrorMessage) + if cmdResults.GetErrors() != nil { + return errorutils.CheckErrorf(cmdResults.GetErrors().Error()) } log.Info("Scan completed successfully.") return nil @@ -346,14 +315,14 @@ func (scanCmd *ScanCommand) CommandName() string { return "xr_scan" } -func (scanCmd *ScanCommand) prepareScanTasks(fileProducer, indexedFileProducer parallel.Runner, jasFileProducerConsumer *utils.SecurityParallelRunner, cmdResults *results.ScanCommandResults, resultsArr [][]*ScanInfo, fileErrors, indexedFileErrors, jasErrors [][]formats.SimpleJsonError, fileCollectingErrorsQueue *clientutils.ErrorsQueue, xrayVersion string) { +func (scanCmd *ScanCommand) prepareScanTasks(fileProducer, indexedFileProducer parallel.Runner, jasFileProducerConsumer *utils.SecurityParallelRunner, cmdResults *results.SecurityCommandResults, fileCollectingErrorsQueue *clientutils.ErrorsQueue) { go func() { defer fileProducer.Done() // Iterate over file-spec groups and produce indexing tasks. // When encountering an error, log and move to next group. specFiles := scanCmd.spec.Files for i := range specFiles { - artifactHandlerFunc := scanCmd.createIndexerHandlerFunc(&specFiles[i], cmdResults, indexedFileProducer, jasFileProducerConsumer, resultsArr, fileErrors, indexedFileErrors, jasErrors, xrayVersion) + artifactHandlerFunc := scanCmd.createIndexerHandlerFunc(&specFiles[i], cmdResults, indexedFileProducer, jasFileProducerConsumer) taskHandler := getAddTaskToProducerFunc(fileProducer, artifactHandlerFunc) err := collectFilesForIndexing(specFiles[i], taskHandler) @@ -365,19 +334,20 @@ func (scanCmd *ScanCommand) prepareScanTasks(fileProducer, indexedFileProducer p }() } -func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, cmdResults *results.ScanCommandResults, indexedFileProducer parallel.Runner, jasFileProducerConsumer *utils.SecurityParallelRunner, resultsArr [][]*ScanInfo, fileErrors, indexedFileErrors, jasErrors [][]formats.SimpleJsonError, xrayVersion string) FileContext { +func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, cmdResults *results.SecurityCommandResults, indexedFileProducer parallel.Runner, jasFileProducerConsumer *utils.SecurityParallelRunner) FileContext { return func(filePath string) parallel.TaskFunc { return func(threadId int) (err error) { logMsgPrefix := clientutils.GetLogMsgPrefix(threadId, false) - log.Info(logMsgPrefix+"Indexing file:", filePath) - if scanCmd.progress != nil { - scanCmd.progress.SetHeadlineMsg("Indexing file: " + filepath.Base(filePath) + " 🗄") - } // Create a scan target for the file. targetResults := cmdResults.NewScanResults(results.ScanTarget{Target: filePath, Name: filepath.Base(filePath)}) - graph, err := scanCmd.indexFile(filePath) + log.Info(logMsgPrefix+"Indexing file:", targetResults.Target) + if scanCmd.progress != nil { + scanCmd.progress.SetHeadlineMsg("Indexing file: " + targetResults.Name + " 🗄") + } + // Index the file and get the dependencies graph. + graph, err := scanCmd.indexFile(targetResults.Target) if err != nil { - fileErrors[threadId] = append(fileErrors[threadId], formats.SimpleJsonError{FilePath: filePath, ErrorMessage: err.Error()}) + targetResults.AddError(err) return err } // In case of empty graph returned by the indexer, @@ -388,7 +358,7 @@ func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, cmdResults } // Add a new task to the second producer/consumer // which will send the indexed binary to Xray and then will store the received result. - taskFunc := func(threadId int) (err error) { + taskFunc := func(scanThreadId int) (err error) { params := &services.XrayGraphScanParams{ BinaryGraph: graph, RepoPath: getXrayRepoPathFromTarget(file.Target), @@ -404,7 +374,7 @@ func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, cmdResults scanGraphParams := scangraph.NewScanGraphParams(). SetServerDetails(scanCmd.serverDetails). SetXrayGraphScanParams(params). - SetXrayVersion(xrayVersion). + SetXrayVersion(cmdResults.XrayVersion). SetFixableOnly(scanCmd.fixableOnly). SetSeverityLevel(scanCmd.minSeverityFilter.String()) xrayManager, err := xray.CreateXrayServiceManager(scanGraphParams.ServerDetails()) @@ -413,49 +383,58 @@ func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, cmdResults } graphScanResults, err := scangraph.RunScanGraphAndGetResults(scanGraphParams, xrayManager) if err != nil { - log.Error(fmt.Sprintf("scanning '%s' failed with error: %s", graph.Id, err.Error())) - indexedFileErrors[threadId] = append(indexedFileErrors[threadId], formats.SimpleJsonError{FilePath: filePath, ErrorMessage: err.Error()}) + log.Error(fmt.Sprintf("%s sca scanning '%s' failed with error: %s", clientutils.GetLogMsgPrefix(scanThreadId, false), graph.Id, err.Error())) + targetResults.AddError(err) return + } else { + targetResults.NewScaScanResults(graphScanResults) + targetResults.Technology = techutils.Technology(graphScanResults.ScannedPackageType) } - - scanResults := utils.ScanCommandResults{ - ScaResults: []*utils.ScaScanResult{{XrayResults: []services.ScanResponse{*graphScanResults}}}, - ExtendedScanResults: &utils.ExtendedScanResults{}, + if !cmdResults.EntitledForJas { + return + } + // Run Jas scans + scanner, err := getJasScanner(filePath, scanCmd.serverDetails, targetResults) + if err != nil { + return err } - if entitledForJas && scanCmd.commandSupportsJAS { - // Run Jas scans - jasErrHandlerFunc := func(err error) { - jasErrors[threadId] = append(jasErrors[threadId], formats.SimpleJsonError{FilePath: filePath, ErrorMessage: err.Error()}) - } - workingDirs := []string{filePath} - depsList := depsListFromVulnerabilities(*graphScanResults) - jfrogAppsConfig, err := jas.CreateJFrogAppsConfig(workingDirs) - if err != nil { - log.Error(fmt.Sprintf("failed to create JFrogAppsConfig: %s", err.Error())) - indexedFileErrors[threadId] = append(indexedFileErrors[threadId], formats.SimpleJsonError{FilePath: filePath, ErrorMessage: err.Error()}) - } - scanner := &jas.JasScanner{} - scanner, err = jas.CreateJasScanner(scanner, jfrogAppsConfig, scanCmd.serverDetails) - if err != nil { - log.Error(fmt.Sprintf("failed to create jas scanner: %s", err.Error())) - indexedFileErrors[threadId] = append(indexedFileErrors[threadId], formats.SimpleJsonError{FilePath: filePath, ErrorMessage: err.Error()}) - } - err = runner.AddJasScannersTasks(jasFileProducerConsumer, &scanResults, []techutils.Technology{techutils.Technology(graphScanResults.ScannedPackageType)}, &depsList, scanCmd.serverDetails, false, "", scanner, applicability.ApplicabilityDockerScanScanType, secrets.SecretsScannerDockerScanType, jasErrHandlerFunc, utils.GetAllSupportedScans()) - if err != nil { - log.Error(fmt.Sprintf("scanning '%s' failed with error: %s", graph.Id, err.Error())) - indexedFileErrors[threadId] = append(indexedFileErrors[threadId], formats.SimpleJsonError{FilePath: filePath, ErrorMessage: err.Error()}) - } + module, err := getJasModule(targetResults) + if err != nil { + return err + } + err = runner.AddJasScannersTasks(jasFileProducerConsumer, module, targetResults, []techutils.Technology{targetResults.Technology}, directDepsListFromVulnerabilities(*graphScanResults), scanCmd.serverDetails, false, "", scanner, applicability.ApplicabilityDockerScanScanType, secrets.SecretsScannerDockerScanType, utils.GetAllSupportedScans()) + if err != nil { + log.Error(fmt.Sprintf("%s jas scanning failed with error: %s", clientutils.GetLogMsgPrefix(scanThreadId, false), err.Error())) + targetResults.AddError(err) } - resultsArr[threadId] = append(resultsArr[threadId], &ScanInfo{Target: filePath, Result: graphScanResults, ExtendedScanResults: scanResults.ExtendedScanResults}) return } - _, _ = indexedFileProducer.AddTask(taskFunc) return } } } +func getJasScanner(filePath string, serverDetails *config.ServerDetails, targetResults *results.TargetResults) (*jas.JasScanner, error) { + scanner, err := jas.CreateJasScanner(&jas.JasScanner{}, serverDetails) + if err != nil { + log.Error(fmt.Sprintf("failed to create jas scanner: %s", err.Error())) + targetResults.AddError(err) + return nil, err + } + return scanner, nil +} + +func getJasModule(targetResults *results.TargetResults) (jfrogappsconfig.Module, error) { + jfrogAppsConfig, err := jas.CreateJFrogAppsConfig([]string{targetResults.Target}) + if err != nil { + log.Error(fmt.Sprintf("failed to create JFrogAppsConfig module: %s", err.Error())) + targetResults.AddError(err) + return jfrogappsconfig.Module{}, err + } + return jfrogAppsConfig.Modules[0], nil +} + func getAddTaskToProducerFunc(producer parallel.Runner, fileHandlerFunc FileContext) indexFileHandlerFunc { return func(filePath string) { taskFunc := fileHandlerFunc(filePath) @@ -555,7 +534,8 @@ func appendErrorSlice(scanErrors []formats.SimpleJsonError, errorsToAdd [][]form return scanErrors } -func depsListFromVulnerabilities(scanResult ...services.ScanResponse) (depsList []string) { +func directDepsListFromVulnerabilities(scanResult ...services.ScanResponse) *[]string { + depsList := []string{} for _, result := range scanResult { for _, vulnerability := range result.Vulnerabilities { dependencies := maps.Keys(vulnerability.Components) @@ -566,7 +546,7 @@ func depsListFromVulnerabilities(scanResult ...services.ScanResponse) (depsList } } } - return + return &depsList } func ConditionalUploadDefaultScanFunc(serverDetails *config.ServerDetails, fileSpec *spec.SpecFiles, threads int, scanOutputFormat format.OutputFormat) error { diff --git a/jas/applicability/applicabilitymanager_test.go b/jas/applicability/applicabilitymanager_test.go index ff2e838e..ab3fab24 100644 --- a/jas/applicability/applicabilitymanager_test.go +++ b/jas/applicability/applicabilitymanager_test.go @@ -37,12 +37,12 @@ func TestNewApplicabilityScanManager_DependencyTreeDoesntExist(t *testing.T) { scanner, cleanUp := jas.InitJasTest(t) defer cleanUp() // Act - applicabilityManager := newApplicabilityScanManager(jas.FakeBasicXrayResults, nil, scanner, false, ApplicabilityScannerType, "temoDirPath") + applicabilityManager := newApplicabilityScanManager(jas.FakeBasicXrayResults, nil, scanner, false, ApplicabilityScannerType, "tempDirPath") // Assert if assert.NotNil(t, applicabilityManager) { assert.NotNil(t, applicabilityManager.scanner.ScannerDirCleanupFunc) - assert.Len(t, applicabilityManager.scanner.JFrogAppsConfig.Modules, 1) + // assert.Len(t, applicabilityManager.scanner.JFrogAppsConfig.Modules, 1) assert.NotEmpty(t, applicabilityManager.configFileName) assert.NotEmpty(t, applicabilityManager.resultsFileName) assert.Empty(t, applicabilityManager.directDependenciesCves) @@ -300,6 +300,8 @@ func TestParseResults_NewApplicabilityStatuses(t *testing.T) { // Arrange scanner, cleanUp := jas.InitJasTest(t) defer cleanUp() + jfrogAppsConfigForTest, err := jas.CreateJFrogAppsConfig([]string{}) + assert.NoError(t, err) scannerTempDir, err := jas.CreateScannerTempDirectory(scanner, string(jasutils.Applicability)) require.NoError(t, err) @@ -310,7 +312,7 @@ func TestParseResults_NewApplicabilityStatuses(t *testing.T) { t.Run(tc.name, func(t *testing.T) { applicabilityManager.resultsFileName = filepath.Join(jas.GetTestDataPath(), "applicability-scan", tc.fileName) var err error - applicabilityManager.applicabilityScanResults, err = jas.ReadJasScanRunsFromFile(applicabilityManager.resultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, applicabilityDocsUrlSuffix) + applicabilityManager.applicabilityScanResults, err = jas.ReadJasScanRunsFromFile(applicabilityManager.resultsFileName, jfrogAppsConfigForTest.Modules[0].SourceRoot, applicabilityDocsUrlSuffix) if assert.NoError(t, err) && assert.NotNil(t, applicabilityManager.applicabilityScanResults) { assert.Len(t, applicabilityManager.applicabilityScanResults, 1) assert.Len(t, applicabilityManager.applicabilityScanResults[0].Results, tc.expectedResults) diff --git a/jas/common.go b/jas/common.go index 65ddd1df..b198dd4b 100644 --- a/jas/common.go +++ b/jas/common.go @@ -37,12 +37,12 @@ type JasScanner struct { TempDir string AnalyzerManager AnalyzerManager ServerDetails *config.ServerDetails - JFrogAppsConfig *jfrogappsconfig.JFrogAppsConfig + // JFrogAppsConfig *jfrogappsconfig.JFrogAppsConfig ScannerDirCleanupFunc func() error Exclusions []string } -func CreateJasScanner(scanner *JasScanner, jfrogAppsConfig *jfrogappsconfig.JFrogAppsConfig, serverDetails *config.ServerDetails, exclusions ...string) (*JasScanner, error) { +func CreateJasScanner(scanner *JasScanner, serverDetails *config.ServerDetails, exclusions ...string) (*JasScanner, error) { var err error if scanner.AnalyzerManager.AnalyzerManagerFullPath, err = GetAnalyzerManagerExecutable(); err != nil { return scanner, err @@ -56,7 +56,7 @@ func CreateJasScanner(scanner *JasScanner, jfrogAppsConfig *jfrogappsconfig.JFro return fileutils.RemoveTempDir(tempDir) } scanner.ServerDetails = serverDetails - scanner.JFrogAppsConfig = jfrogAppsConfig + // scanner.JFrogAppsConfig = jfrogAppsConfig scanner.Exclusions = exclusions return scanner, err } @@ -198,12 +198,10 @@ var FakeBasicXrayResults = []services.ScanResponse{ }, } -func InitJasTest(t *testing.T, workingDirs ...string) (*JasScanner, func()) { +func InitJasTest(t *testing.T) (*JasScanner, func()) { assert.NoError(t, DownloadAnalyzerManagerIfNeeded(0)) - jfrogAppsConfigForTest, err := CreateJFrogAppsConfig(workingDirs) - assert.NoError(t, err) scanner := &JasScanner{} - scanner, err = CreateJasScanner(scanner, jfrogAppsConfigForTest, &FakeServerDetails) + scanner, err := CreateJasScanner(scanner, &FakeServerDetails) assert.NoError(t, err) return scanner, func() { assert.NoError(t, scanner.ScannerDirCleanupFunc()) @@ -214,6 +212,15 @@ func GetTestDataPath() string { return filepath.Join("..", "..", "tests", "testdata", "other") } +func GetModule(root string, appConfig *jfrogappsconfig.JFrogAppsConfig) *jfrogappsconfig.Module { + for _, module := range appConfig.Modules { + if module.SourceRoot == root { + return &module + } + } + return nil +} + func ShouldSkipScanner(module jfrogappsconfig.Module, scanType jasutils.JasScanType) bool { lowerScanType := strings.ToLower(string(scanType)) if slices.Contains(module.ExcludeScanners, lowerScanType) { diff --git a/jas/iac/iacscanner_test.go b/jas/iac/iacscanner_test.go index de49351e..023ef52d 100644 --- a/jas/iac/iacscanner_test.go +++ b/jas/iac/iacscanner_test.go @@ -16,8 +16,10 @@ import ( ) func TestNewIacScanManager(t *testing.T) { - scanner, cleanUp := jas.InitJasTest(t, "currentDir") + scanner, cleanUp := jas.InitJasTest(t) defer cleanUp() + jfrogAppsConfigForTest, err := jas.CreateJFrogAppsConfig([]string{"currentDir"}) + assert.NoError(t, err) // Act iacScanManager := newIacScanManager(scanner, "temoDirPath") @@ -26,13 +28,13 @@ func TestNewIacScanManager(t *testing.T) { if assert.NotNil(t, iacScanManager) { assert.NotEmpty(t, iacScanManager.configFileName) assert.NotEmpty(t, iacScanManager.resultsFileName) - assert.NotEmpty(t, iacScanManager.scanner.JFrogAppsConfig.Modules[0].SourceRoot) + assert.NotEmpty(t, jfrogAppsConfigForTest.Modules[0].SourceRoot) assert.Equal(t, &jas.FakeServerDetails, iacScanManager.scanner.ServerDetails) } } func TestIacScan_CreateConfigFile_VerifyFileWasCreated(t *testing.T) { - scanner, cleanUp := jas.InitJasTest(t, "currentDir") + scanner, cleanUp := jas.InitJasTest(t) defer cleanUp() scannerTempDir, err := jas.CreateScannerTempDirectory(scanner, jasutils.IaC.String()) @@ -58,14 +60,15 @@ func TestIacScan_CreateConfigFile_VerifyFileWasCreated(t *testing.T) { func TestIacParseResults_EmptyResults(t *testing.T) { scanner, cleanUp := jas.InitJasTest(t) defer cleanUp() + jfrogAppsConfigForTest, err := jas.CreateJFrogAppsConfig([]string{}) + assert.NoError(t, err) // Arrange iacScanManager := newIacScanManager(scanner, "temoDirPath") iacScanManager.resultsFileName = filepath.Join(jas.GetTestDataPath(), "iac-scan", "no-violations.sarif") // Act - var err error - iacScanManager.iacScannerResults, err = jas.ReadJasScanRunsFromFile(iacScanManager.resultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, iacDocsUrlSuffix) + iacScanManager.iacScannerResults, err = jas.ReadJasScanRunsFromFile(iacScanManager.resultsFileName, jfrogAppsConfigForTest.Modules[0].SourceRoot, iacDocsUrlSuffix) if assert.NoError(t, err) && assert.NotNil(t, iacScanManager.iacScannerResults) { assert.Len(t, iacScanManager.iacScannerResults, 1) assert.Empty(t, iacScanManager.iacScannerResults[0].Results) @@ -75,13 +78,14 @@ func TestIacParseResults_EmptyResults(t *testing.T) { func TestIacParseResults_ResultsContainIacViolations(t *testing.T) { scanner, cleanUp := jas.InitJasTest(t) defer cleanUp() + jfrogAppsConfigForTest, err := jas.CreateJFrogAppsConfig([]string{}) + assert.NoError(t, err) // Arrange iacScanManager := newIacScanManager(scanner, "temoDirPath") iacScanManager.resultsFileName = filepath.Join(jas.GetTestDataPath(), "iac-scan", "contains-iac-violations.sarif") // Act - var err error - iacScanManager.iacScannerResults, err = jas.ReadJasScanRunsFromFile(iacScanManager.resultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, iacDocsUrlSuffix) + iacScanManager.iacScannerResults, err = jas.ReadJasScanRunsFromFile(iacScanManager.resultsFileName, jfrogAppsConfigForTest.Modules[0].SourceRoot, iacDocsUrlSuffix) if assert.NoError(t, err) && assert.NotNil(t, iacScanManager.iacScannerResults) { assert.Len(t, iacScanManager.iacScannerResults, 1) assert.Len(t, iacScanManager.iacScannerResults[0].Results, 4) diff --git a/jas/runner/jasrunner.go b/jas/runner/jasrunner.go index 76b1362b..0073b5cb 100644 --- a/jas/runner/jasrunner.go +++ b/jas/runner/jasrunner.go @@ -20,8 +20,8 @@ import ( "golang.org/x/exp/slices" ) -func AddJasScannersTasks(securityParallelRunner *utils.SecurityParallelRunner, scanResults *results.ScanCommandResults, technologiesList []techutils.Technology, directDependencies *[]string, - serverDetails *config.ServerDetails, thirdPartyApplicabilityScan bool, msi string, scanner *jas.JasScanner, scanType applicability.ApplicabilityScanType, secretsScanType secrets.SecretsScanType, errHandlerFunc func(error), scansToPreform []utils.SubScanType) (err error) { +func AddJasScannersTasks(securityParallelRunner *utils.SecurityParallelRunner, module jfrogappsconfig.Module, scanResults *results.TargetResults, technologiesList []techutils.Technology, directDependencies *[]string, + serverDetails *config.ServerDetails, thirdPartyApplicabilityScan bool, msi string, scanner *jas.JasScanner, scanType applicability.ApplicabilityScanType, secretsScanType secrets.SecretsScanType, scansToPreform []utils.SubScanType) (err error) { if serverDetails == nil || len(serverDetails.Url) == 0 { log.Warn("To include 'Advanced Security' scan as part of the audit output, please run the 'jf c add' command before running this command.") return @@ -36,52 +36,51 @@ func AddJasScannersTasks(securityParallelRunner *utils.SecurityParallelRunner, s defer func() { callback() }() - // Don't execute other scanners when scanning third party dependencies. - if !thirdPartyApplicabilityScan { - for _, module := range scanner.JFrogAppsConfig.Modules { - if len(scansToPreform) > 0 && !slices.Contains(scansToPreform, utils.SecretsScan) { - log.Debug("Skipping secrets scan as requested by input...") - } else if err = addModuleJasScanTask(module, jasutils.Secrets, securityParallelRunner, runSecretsScan(securityParallelRunner, scanner, scanResults.ExtendedScanResults, module, secretsScanType), errHandlerFunc); err != nil { - return - } - if runAllScanners { - if len(scansToPreform) > 0 && !slices.Contains(scansToPreform, utils.IacScan) { - log.Debug("Skipping Iac scan as requested by input...") - } else if err = addModuleJasScanTask(module, jasutils.IaC, securityParallelRunner, runIacScan(securityParallelRunner, scanner, scanResults.ExtendedScanResults, module), errHandlerFunc); err != nil { - return - } - if len(scansToPreform) > 0 && !slices.Contains(scansToPreform, utils.SastScan) { - log.Debug("Skipping Sast scan as requested by input...") - } else if err = addModuleJasScanTask(module, jasutils.Sast, securityParallelRunner, runSastScan(securityParallelRunner, scanner, scanResults.ExtendedScanResults, module), errHandlerFunc); err != nil { - return - } - } - } - } if len(scansToPreform) > 0 && !slices.Contains(scansToPreform, utils.ContextualAnalysisScan) { log.Debug("Skipping contextual analysis scan as requested by input...") return err } - for _, module := range scanner.JFrogAppsConfig.Modules { - if err = addModuleJasScanTask(module, jasutils.Applicability, securityParallelRunner, runContextualScan(securityParallelRunner, scanner, scanResults, module, directDependencies, thirdPartyApplicabilityScan, scanType), errHandlerFunc); err != nil { + if err = addModuleJasScanTask(module, jasutils.Applicability, securityParallelRunner, runContextualScan(securityParallelRunner, scanner, scanResults, module, directDependencies, thirdPartyApplicabilityScan, scanType), scanResults); err != nil { + return + } + // Don't execute other scanners when scanning third party dependencies. + if thirdPartyApplicabilityScan { + return + } + if len(scansToPreform) > 0 && !slices.Contains(scansToPreform, utils.SecretsScan) { + log.Debug("Skipping secrets scan as requested by input...") + } else if err = addModuleJasScanTask(module, jasutils.Secrets, securityParallelRunner, runSecretsScan(securityParallelRunner, scanner, scanResults.JasResults, module, secretsScanType), scanResults); err != nil { + return + } + if runAllScanners { + if len(scansToPreform) > 0 && !slices.Contains(scansToPreform, utils.IacScan) { + log.Debug("Skipping Iac scan as requested by input...") + } else if err = addModuleJasScanTask(module, jasutils.IaC, securityParallelRunner, runIacScan(securityParallelRunner, scanner, scanResults.JasResults, module), scanResults); err != nil { + return + } + if len(scansToPreform) > 0 && !slices.Contains(scansToPreform, utils.SastScan) { + log.Debug("Skipping Sast scan as requested by input...") + } else if err = addModuleJasScanTask(module, jasutils.Sast, securityParallelRunner, runSastScan(securityParallelRunner, scanner, scanResults.JasResults, module), scanResults); err != nil { return } } return err } -func addModuleJasScanTask(module jfrogappsconfig.Module, scanType jasutils.JasScanType, securityParallelRunner *utils.SecurityParallelRunner, task parallel.TaskFunc, errHandlerFunc func(error)) (err error) { +func addModuleJasScanTask(module jfrogappsconfig.Module, scanType jasutils.JasScanType, securityParallelRunner *utils.SecurityParallelRunner, task parallel.TaskFunc, scanResults *results.TargetResults) (err error) { if jas.ShouldSkipScanner(module, scanType) { return } securityParallelRunner.JasScannersWg.Add(1) - if _, err = securityParallelRunner.Runner.AddTaskWithError(task, errHandlerFunc); err != nil { + if _, err = securityParallelRunner.Runner.AddTaskWithError(task, func(err error) { + scanResults.AddError(err) + }); err != nil { err = fmt.Errorf("failed to create %s scan task: %s", scanType, err.Error()) } return } -func runSecretsScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, extendedScanResults *results.ExtendedScanResults, +func runSecretsScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, extendedScanResults *results.JasScansResults, module jfrogappsconfig.Module, secretsScanType secrets.SecretsScanType) parallel.TaskFunc { return func(threadId int) (err error) { defer func() { @@ -98,7 +97,7 @@ func runSecretsScan(securityParallelRunner *utils.SecurityParallelRunner, scanne } } -func runIacScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, extendedScanResults *results.ExtendedScanResults, +func runIacScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, extendedScanResults *results.JasScansResults, module jfrogappsconfig.Module) parallel.TaskFunc { return func(threadId int) (err error) { defer func() { @@ -115,7 +114,7 @@ func runIacScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *j } } -func runSastScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, extendedScanResults *results.ExtendedScanResults, +func runSastScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, extendedScanResults *results.JasScansResults, module jfrogappsconfig.Module) parallel.TaskFunc { return func(threadId int) (err error) { defer func() { @@ -132,7 +131,7 @@ func runSastScan(securityParallelRunner *utils.SecurityParallelRunner, scanner * } } -func runContextualScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, scanResults *results.ScanCommandResults, +func runContextualScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *jas.JasScanner, scanResults *results.TargetResults, module jfrogappsconfig.Module, directDependencies *[]string, thirdPartyApplicabilityScan bool, scanType applicability.ApplicabilityScanType) parallel.TaskFunc { return func(threadId int) (err error) { defer func() { @@ -145,7 +144,7 @@ func runContextualScan(securityParallelRunner *utils.SecurityParallelRunner, sca return fmt.Errorf("%s %s", clientutils.GetLogMsgPrefix(threadId, false), err.Error()) } securityParallelRunner.ResultsMu.Lock() - scanResults.ExtendedScanResults.ApplicabilityScanResults = append(scanResults.ExtendedScanResults.ApplicabilityScanResults, results...) + scanResults.JasResults.ApplicabilityScanResults = append(scanResults.JasResults.ApplicabilityScanResults, results...) securityParallelRunner.ResultsMu.Unlock() return } diff --git a/jas/runner/jasrunner_test.go b/jas/runner/jasrunner_test.go index 4ecc8ac2..2dfd23c7 100644 --- a/jas/runner/jasrunner_test.go +++ b/jas/runner/jasrunner_test.go @@ -4,6 +4,7 @@ import ( "os" "testing" + jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" "github.com/jfrog/jfrog-cli-core/v2/common/cliutils" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" @@ -28,7 +29,7 @@ func TestGetExtendedScanResults_AnalyzerManagerDoesntExist(t *testing.T) { assert.NoError(t, os.Unsetenv(coreutils.HomeDir)) }() scanner := &jas.JasScanner{} - _, err = jas.CreateJasScanner(scanner, nil, &jas.FakeServerDetails) + _, err = jas.CreateJasScanner(scanner, &jas.FakeServerDetails) assert.Error(t, err) assert.ErrorContains(t, err, "unable to locate the analyzer manager package. Advanced security scans cannot be performed without this package") } @@ -36,10 +37,11 @@ func TestGetExtendedScanResults_AnalyzerManagerDoesntExist(t *testing.T) { func TestGetExtendedScanResults_ServerNotValid(t *testing.T) { securityParallelRunnerForTest := utils.CreateSecurityParallelRunner(cliutils.Threads) scanner := &jas.JasScanner{} - jasScanner, err := jas.CreateJasScanner(scanner, nil, &jas.FakeServerDetails) + jasScanner, err := jas.CreateJasScanner(scanner, &jas.FakeServerDetails) assert.NoError(t, err) - scanResults := &results.ScanCommandResults{ScaResults: []*results.ScaScanResult{{Technology: techutils.Pip, XrayResults: jas.FakeBasicXrayResults}}, ExtendedScanResults: &results.ExtendedScanResults{}} - err = AddJasScannersTasks(securityParallelRunnerForTest, scanResults, scanResults.GetScaScannedTechnologies(), &[]string{"issueId_1_direct_dependency", "issueId_2_direct_dependency"}, nil, false, "", jasScanner, applicability.ApplicabilityScannerType, secrets.SecretsScannerType, securityParallelRunnerForTest.AddErrorToChan, utils.GetAllSupportedScans()) + targetResults := results.NewCommandResults("", true).NewScanResults(results.ScanTarget{Target: "target", Technology: techutils.Pip}) + targetResults.NewScaScanResults(&jas.FakeBasicXrayResults[0]) + err = AddJasScannersTasks(securityParallelRunnerForTest, jfrogappsconfig.Module{}, targetResults, targetResults.GetTechnologies(), &[]string{"issueId_1_direct_dependency", "issueId_2_direct_dependency"}, nil, false, "", jasScanner, applicability.ApplicabilityScannerType, secrets.SecretsScannerType, utils.GetAllSupportedScans()) assert.NoError(t, err) } @@ -48,7 +50,7 @@ func TestGetExtendedScanResults_AnalyzerManagerReturnsError(t *testing.T) { jfrogAppsConfigForTest, _ := jas.CreateJFrogAppsConfig(nil) scanner := &jas.JasScanner{} - scanner, _ = jas.CreateJasScanner(scanner, nil, &jas.FakeServerDetails) + scanner, _ = jas.CreateJasScanner(scanner, &jas.FakeServerDetails) _, err := applicability.RunApplicabilityScan(jas.FakeBasicXrayResults, []string{"issueId_2_direct_dependency", "issueId_1_direct_dependency"}, scanner, false, applicability.ApplicabilityScannerType, jfrogAppsConfigForTest.Modules[0], 0) diff --git a/jas/sast/sastscanner_test.go b/jas/sast/sastscanner_test.go index d136b0b7..9e9aab8a 100644 --- a/jas/sast/sastscanner_test.go +++ b/jas/sast/sastscanner_test.go @@ -12,8 +12,10 @@ import ( ) func TestNewSastScanManager(t *testing.T) { - scanner, cleanUp := jas.InitJasTest(t, "currentDir") + scanner, cleanUp := jas.InitJasTest(t) defer cleanUp() + jfrogAppsConfigForTest, err := jas.CreateJFrogAppsConfig([]string{"currentDir"}) + assert.NoError(t, err) // Act sastScanManager := newSastScanManager(scanner, "temoDirPath") @@ -21,7 +23,7 @@ func TestNewSastScanManager(t *testing.T) { if assert.NotNil(t, sastScanManager) { assert.NotEmpty(t, sastScanManager.configFileName) assert.NotEmpty(t, sastScanManager.resultsFileName) - assert.NotEmpty(t, sastScanManager.scanner.JFrogAppsConfig.Modules[0].SourceRoot) + assert.NotEmpty(t, jfrogAppsConfigForTest.Modules[0].SourceRoot) assert.Equal(t, &jas.FakeServerDetails, sastScanManager.scanner.ServerDetails) } } @@ -29,14 +31,15 @@ func TestNewSastScanManager(t *testing.T) { func TestSastParseResults_EmptyResults(t *testing.T) { scanner, cleanUp := jas.InitJasTest(t) defer cleanUp() + jfrogAppsConfigForTest, err := jas.CreateJFrogAppsConfig([]string{}) + assert.NoError(t, err) // Arrange sastScanManager := newSastScanManager(scanner, "temoDirPath") sastScanManager.resultsFileName = filepath.Join(jas.GetTestDataPath(), "sast-scan", "no-violations.sarif") // Act - var err error - sastScanManager.sastScannerResults, err = jas.ReadJasScanRunsFromFile(sastScanManager.resultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, sastDocsUrlSuffix) + sastScanManager.sastScannerResults, err = jas.ReadJasScanRunsFromFile(sastScanManager.resultsFileName, jfrogAppsConfigForTest.Modules[0].SourceRoot, sastDocsUrlSuffix) // Assert if assert.NoError(t, err) && assert.NotNil(t, sastScanManager.sastScannerResults) { @@ -51,13 +54,14 @@ func TestSastParseResults_EmptyResults(t *testing.T) { func TestSastParseResults_ResultsContainIacViolations(t *testing.T) { scanner, cleanUp := jas.InitJasTest(t) defer cleanUp() + jfrogAppsConfigForTest, err := jas.CreateJFrogAppsConfig([]string{}) + assert.NoError(t, err) // Arrange sastScanManager := newSastScanManager(scanner, "temoDirPath") sastScanManager.resultsFileName = filepath.Join(jas.GetTestDataPath(), "sast-scan", "contains-sast-violations.sarif") // Act - var err error - sastScanManager.sastScannerResults, err = jas.ReadJasScanRunsFromFile(sastScanManager.resultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, sastDocsUrlSuffix) + sastScanManager.sastScannerResults, err = jas.ReadJasScanRunsFromFile(sastScanManager.resultsFileName, jfrogAppsConfigForTest.Modules[0].SourceRoot, sastDocsUrlSuffix) // Assert if assert.NoError(t, err) && assert.NotNil(t, sastScanManager.sastScannerResults) { diff --git a/jas/secrets/secretsscanner_test.go b/jas/secrets/secretsscanner_test.go index c6473e54..e46b824d 100644 --- a/jas/secrets/secretsscanner_test.go +++ b/jas/secrets/secretsscanner_test.go @@ -66,13 +66,14 @@ func TestRunAnalyzerManager_ReturnsGeneralError(t *testing.T) { func TestParseResults_EmptyResults(t *testing.T) { scanner, cleanUp := jas.InitJasTest(t) defer cleanUp() + jfrogAppsConfigForTest, err := jas.CreateJFrogAppsConfig([]string{}) + assert.NoError(t, err) // Arrange secretScanManager := newSecretsScanManager(scanner, SecretsScannerType, "temoDirPath") secretScanManager.resultsFileName = filepath.Join(jas.GetTestDataPath(), "secrets-scan", "no-secrets.sarif") // Act - var err error - secretScanManager.secretsScannerResults, err = jas.ReadJasScanRunsFromFile(secretScanManager.resultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, secretsDocsUrlSuffix) + secretScanManager.secretsScannerResults, err = jas.ReadJasScanRunsFromFile(secretScanManager.resultsFileName, jfrogAppsConfigForTest.Modules[0].SourceRoot, secretsDocsUrlSuffix) // Assert if assert.NoError(t, err) && assert.NotNil(t, secretScanManager.secretsScannerResults) { @@ -89,13 +90,14 @@ func TestParseResults_ResultsContainSecrets(t *testing.T) { // Arrange scanner, cleanUp := jas.InitJasTest(t) defer cleanUp() + jfrogAppsConfigForTest, err := jas.CreateJFrogAppsConfig([]string{}) + assert.NoError(t, err) secretScanManager := newSecretsScanManager(scanner, SecretsScannerType, "temoDirPath") secretScanManager.resultsFileName = filepath.Join(jas.GetTestDataPath(), "secrets-scan", "contain-secrets.sarif") // Act - var err error - secretScanManager.secretsScannerResults, err = jas.ReadJasScanRunsFromFile(secretScanManager.resultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, secretsDocsUrlSuffix) + secretScanManager.secretsScannerResults, err = jas.ReadJasScanRunsFromFile(secretScanManager.resultsFileName, jfrogAppsConfigForTest.Modules[0].SourceRoot, secretsDocsUrlSuffix) // Assert if assert.NoError(t, err) && assert.NotNil(t, secretScanManager.secretsScannerResults) { @@ -112,7 +114,9 @@ func TestParseResults_ResultsContainSecrets(t *testing.T) { func TestGetSecretsScanResults_AnalyzerManagerReturnsError(t *testing.T) { scanner, cleanUp := jas.InitJasTest(t) defer cleanUp() - scanResults, err := RunSecretsScan(scanner, SecretsScannerType, scanner.JFrogAppsConfig.Modules[0], 0) + jfrogAppsConfigForTest, err := jas.CreateJFrogAppsConfig([]string{}) + assert.NoError(t, err) + scanResults, err := RunSecretsScan(scanner, SecretsScannerType, jfrogAppsConfigForTest.Modules[0], 0) assert.Error(t, err) assert.ErrorContains(t, err, "failed to run Secrets scan") assert.Nil(t, scanResults) diff --git a/utils/results/common.go b/utils/results/common.go index 7c3ab6e3..1655f653 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -411,11 +411,11 @@ func getImpactPathKey(path []services.ImpactPathNode) string { return key } -func SplitScaScanResults(results *ScanCommandResults) ([]services.Violation, []services.Vulnerability, []services.License) { +func SplitScaScanResults(results *SecurityCommandResults) ([]services.Violation, []services.Vulnerability, []services.License) { var violations []services.Violation var vulnerabilities []services.Vulnerability var licenses []services.License - for _, scan := range results.Scans { + for _, scan := range results.Targets { for _, scaScan := range scan.ScaResults { violations = append(violations, scaScan.XrayResult.Violations...) vulnerabilities = append(vulnerabilities, scaScan.XrayResult.Vulnerabilities...) diff --git a/utils/results/conversion/convertor.go b/utils/results/conversion/convertor.go index 754ca532..0e912215 100644 --- a/utils/results/conversion/convertor.go +++ b/utils/results/conversion/convertor.go @@ -55,7 +55,7 @@ type ResultsStreamFormatParser interface { ParseSast(target string, sast ...*sarif.Run) error } -func (c *CommandResultsConvertor) ConvertToSimpleJson(cmdResults *results.ScanCommandResults) (simpleJsonResults formats.SimpleJsonResults, err error) { +func (c *CommandResultsConvertor) ConvertToSimpleJson(cmdResults *results.SecurityCommandResults) (simpleJsonResults formats.SimpleJsonResults, err error) { parser := simplejsonparser.NewCmdResultsSimpleJsonConverter(false) err = c.parseCommandResults(parser, cmdResults) if err != nil { @@ -70,7 +70,7 @@ func (c *CommandResultsConvertor) ConvertToSimpleJson(cmdResults *results.ScanCo return } -func (c *CommandResultsConvertor) ConvertToSarif(cmdResults *results.ScanCommandResults) (sarifReport *sarif.Report, err error) { +func (c *CommandResultsConvertor) ConvertToSarif(cmdResults *results.SecurityCommandResults) (sarifReport *sarif.Report, err error) { parser := sarifparser.NewCmdResultsSarifConverter(c.Params.Pretty, c.Params.AllowResultsWithoutLocations) err = c.parseCommandResults(parser, cmdResults) if err != nil { @@ -79,7 +79,7 @@ func (c *CommandResultsConvertor) ConvertToSarif(cmdResults *results.ScanCommand return parser.Get() } -func (c *CommandResultsConvertor) ConvertToTable(cmdResults *results.ScanCommandResults) (tableResults formats.ResultsTables, err error) { +func (c *CommandResultsConvertor) ConvertToTable(cmdResults *results.SecurityCommandResults) (tableResults formats.ResultsTables, err error) { parser := tableparser.NewCmdResultsTableConverter(c.Params.Pretty) err = c.parseCommandResults(parser, cmdResults) if err != nil { @@ -94,7 +94,7 @@ func (c *CommandResultsConvertor) ConvertToTable(cmdResults *results.ScanCommand return } -func (c *CommandResultsConvertor) ConvertToSummary(cmdResults *results.ScanCommandResults) (summaryResults formats.SummaryResults, err error) { +func (c *CommandResultsConvertor) ConvertToSummary(cmdResults *results.SecurityCommandResults) (summaryResults formats.SummaryResults, err error) { parser := summaryparser.NewCmdResultsSummaryConverter() err = c.parseCommandResults(parser, cmdResults) if err != nil { @@ -103,11 +103,11 @@ func (c *CommandResultsConvertor) ConvertToSummary(cmdResults *results.ScanComma return *parser.Get(), nil } -func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormatParser, cmdResults *results.ScanCommandResults) (err error) { +func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormatParser, cmdResults *results.SecurityCommandResults) (err error) { jasEntitled := cmdResults.EntitledForJas multipleTargets := cmdResults.HasMultipleTargets() parser.Reset(cmdResults.MultiScanId, cmdResults.XrayVersion, jasEntitled) - for _, scan := range cmdResults.Scans { + for _, scan := range cmdResults.Targets { if err = parser.ParseNewScanResultsMetadata(scan.Target, scan.Error); err != nil { return err } diff --git a/utils/results/output/resultwriter.go b/utils/results/output/resultwriter.go index 9a40c32a..81f9958b 100644 --- a/utils/results/output/resultwriter.go +++ b/utils/results/output/resultwriter.go @@ -1 +1,291 @@ -package output \ No newline at end of file +package output + +import ( + "bytes" + "encoding/json" + "os" + + "github.com/jfrog/jfrog-cli-core/v2/common/format" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/results/conversion" + "github.com/jfrog/jfrog-client-go/utils/errorutils" + "github.com/jfrog/jfrog-client-go/utils/io/fileutils" + "github.com/jfrog/jfrog-client-go/utils/log" + "github.com/jfrog/jfrog-client-go/xray/services" +) + +type ResultsWriter struct { + // The scan commandResults. + commandResults *results.SecurityCommandResults + // Format The output format. + format format.OutputFormat + // IncludeVulnerabilities If true, include all vulnerabilities as part of the output. Else, include violations only. + includeVulnerabilities bool + // IncludeLicenses If true, also include license violations as part of the output. + includeLicenses bool + // PrintExtended, If true, show extended results. + printExtended bool + // The scanType (binary,dependency) + scanType services.ScanType + // Messages - Option array of messages, to be displayed if the format is Table + messages []string +} + +func NewResultsWriter(scanResults *results.SecurityCommandResults) *ResultsWriter { + return &ResultsWriter{commandResults: scanResults} +} + +func (rw *ResultsWriter) SetOutputFormat(f format.OutputFormat) *ResultsWriter { + rw.format = f + return rw +} + +func (rw *ResultsWriter) SetScanType(scanType services.ScanType) *ResultsWriter { + rw.scanType = scanType + return rw +} + +func (rw *ResultsWriter) SetIncludeVulnerabilities(includeVulnerabilities bool) *ResultsWriter { + rw.includeVulnerabilities = includeVulnerabilities + return rw +} + +func (rw *ResultsWriter) SetIncludeLicenses(licenses bool) *ResultsWriter { + rw.includeLicenses = licenses + return rw +} + +func (rw *ResultsWriter) SetPrintExtendedTable(extendedTable bool) *ResultsWriter { + rw.printExtended = extendedTable + return rw +} + +func (rw *ResultsWriter) SetExtraMessages(messages []string) *ResultsWriter { + rw.messages = messages + return rw +} + +func printMessages(messages []string) { + if len(messages) > 0 { + log.Output() + } + for _, m := range messages { + printMessage(m) + } +} + +func printMessage(message string) { + log.Output("💬" + message) +} + +func isPrettyOutputSupported() bool { + return log.IsStdOutTerminal() && log.IsColorsSupported() || os.Getenv("GITLAB_CI") != "" +} + +// PrintScanResults prints the scan results in the specified format. +// Note that errors are printed only with SimpleJson format. +func (rw *ResultsWriter) PrintScanResults() error { + if rw.commandResults.GetErrors() != nil && !rw.commandResults.HasInformation() { + // Don't print if there are no results and only errors. + return nil + } + switch rw.format { + case format.Table: + return rw.printTables() + case format.SimpleJson: + simpleJson, err := rw.createResultsConvertor(false).ConvertToSimpleJson(rw.commandResults) + if err != nil { + return err + } + return PrintJson(simpleJson) + case format.Json: + if rw.printExtended { + return PrintJson(rw.commandResults) + } + return PrintJson(rw.commandResults.GetScaScansXrayResults()) + case format.Sarif: + return rw.printSarif() + } + return nil +} + +func (rw *ResultsWriter) createResultsConvertor(pretty bool) *conversion.CommandResultsConvertor { + return conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{ + IncludeLicenses: rw.includeLicenses, + IncludeVulnerabilities: rw.includeVulnerabilities, + Pretty: pretty, + AllowResultsWithoutLocations: true, + }) +} + +func (rw *ResultsWriter) printSarif() error { + sarifContent, err := rw.createResultsConvertor(false).ConvertToSarif(rw.commandResults) + if err != nil { + return err + } + sarifFile, err := sarifutils.ConvertSarifReportToString(sarifContent) + if err != nil { + return err + } + log.Output(sarifFile) + return nil +} + +func PrintJson(output interface{}) (err error) { + results, err := utils.GetAsJsonString(output) + if err != nil { + return + } + log.Output(results) + return nil +} + +func (rw *ResultsWriter) printTables() (err error) { + tableContent, err := rw.createResultsConvertor(isPrettyOutputSupported()).ConvertToTable(rw.commandResults) + if err != nil { + return + } + printMessages(rw.messages) + if rw.commandResults.HasInformation() { + var resultsPath string + if resultsPath, err = writeJsonResults(rw.commandResults); err != nil { + return + } + printMessage(coreutils.PrintTitle("The full scan results are available here: ") + coreutils.PrintLink(resultsPath)) + } + log.Output() + if rw.includeVulnerabilities { + err = PrintVulnerabilitiesTable(tableContent, rw.scanType, len(rw.commandResults.GetTechnologies()) > 0, rw.printExtended) + } else { + err = PrintViolationsTable(tableContent, rw.scanType, rw.printExtended) + } + if err != nil { + return + } + if rw.includeLicenses { + if err = PrintLicensesTable(tableContent, rw.printExtended, rw.scanType); err != nil { + return + } + } + if err = PrintJasTable(tableContent, rw.commandResults.EntitledForJas, jasutils.Secrets); err != nil { + return + } + if err = PrintJasTable(tableContent, rw.commandResults.EntitledForJas, jasutils.IaC); err != nil { + return + } + return PrintJasTable(tableContent, rw.commandResults.EntitledForJas, jasutils.Sast) +} + +// PrintVulnerabilitiesTable prints the vulnerabilities in a table. +// Set printExtended to true to print fields with 'extended' tag. +// If the scan argument is set to true, print the scan tables. +func PrintVulnerabilitiesTable(tables formats.ResultsTables, scanType services.ScanType, techDetected, printExtended bool) error { + if scanType == services.Binary { + return coreutils.PrintTable(formats.ConvertSecurityTableRowToScanTableRow(tables.SecurityVulnerabilitiesTable), + "Vulnerable Components", + "✨ No vulnerable components were found ✨", + printExtended, + ) + } + emptyTableMessage := "✨ No vulnerable dependencies were found ✨" + if !techDetected { + emptyTableMessage = coreutils.PrintYellow("🔧 Couldn't determine a package manager or build tool used by this project 🔧") + } + return coreutils.PrintTable(tables.SecurityVulnerabilitiesTable, "Vulnerable Dependencies", emptyTableMessage, printExtended) +} + +// PrintViolationsTable prints the violations in 4 tables: security violations, license compliance violations, operational risk violations and ignore rule URLs. +// Set printExtended to true to print fields with 'extended' tag. +// If the scan argument is set to true, print the scan tables. +func PrintViolationsTable(tables formats.ResultsTables, scanType services.ScanType, printExtended bool) (err error) { + if scanType == services.Binary { + err = coreutils.PrintTable(formats.ConvertSecurityTableRowToScanTableRow(tables.SecurityVulnerabilitiesTable), "Security Violations", "No security violations were found", printExtended) + if err != nil { + return err + } + err = coreutils.PrintTable(formats.ConvertLicenseViolationTableRowToScanTableRow(tables.LicenseViolationsTable), "License Compliance Violations", "No license compliance violations were found", printExtended) + if err != nil { + return err + } + if len(tables.OperationalRiskViolationsTable) > 0 { + return coreutils.PrintTable(formats.ConvertOperationalRiskTableRowToScanTableRow(tables.OperationalRiskViolationsTable), "Operational Risk Violations", "No operational risk violations were found", printExtended) + } + } else { + err = coreutils.PrintTable(tables.SecurityVulnerabilitiesTable, "Security Violations", "No security violations were found", printExtended) + if err != nil { + return err + } + err = coreutils.PrintTable(tables.LicenseViolationsTable, "License Compliance Violations", "No license compliance violations were found", printExtended) + if err != nil { + return err + } + if len(tables.OperationalRiskViolationsTable) > 0 { + return coreutils.PrintTable(tables.OperationalRiskViolationsTable, "Operational Risk Violations", "No operational risk violations were found", printExtended) + } + } + return nil +} + +// PrintLicensesTable prints the licenses in a table. +// Set multipleRoots to true in case the given licenses array contains (or may contain) results of several projects or files (like in binary scan). +// In case multipleRoots is true, the field Component will show the root of each impact path, otherwise it will show the root's child. +// Set printExtended to true to print fields with 'extended' tag. +// If the scan argument is set to true, print the scan tables. +func PrintLicensesTable(tables formats.ResultsTables, printExtended bool, scanType services.ScanType) error { + if scanType == services.Binary { + return coreutils.PrintTable(formats.ConvertLicenseTableRowToScanTableRow(tables.LicensesTable), "Licenses", "No licenses were found", printExtended) + } + return coreutils.PrintTable(tables.LicensesTable, "Licenses", "No licenses were found", printExtended) +} + +func PrintJasTable(tables formats.ResultsTables, entitledForJas bool, scanType jasutils.JasScanType) error { + if !entitledForJas { + return nil + } + log.Output() + switch scanType { + case jasutils.Secrets: + return coreutils.PrintTable(tables.SecretsTable, "Secret Detection", + "✨ No secrets were found ✨", false) + case jasutils.IaC: + return coreutils.PrintTable(tables.IacTable, "Infrastructure as Code Vulnerabilities", + "✨ No Infrastructure as Code vulnerabilities were found ✨", false) + case jasutils.Sast: + return coreutils.PrintTable(tables.SastTable, "Static Application Security Testing (SAST)", + "✨ No Static Application Security Testing vulnerabilities were found ✨", false) + } + return nil +} + +func writeJsonResults(results *results.SecurityCommandResults) (resultsPath string, err error) { + out, err := fileutils.CreateTempFile() + if errorutils.CheckError(err) != nil { + return + } + defer func() { + e := out.Close() + if err == nil { + err = e + } + }() + bytesRes, err := json.Marshal(&results) + if errorutils.CheckError(err) != nil { + return + } + var content bytes.Buffer + err = json.Indent(&content, bytesRes, "", " ") + if errorutils.CheckError(err) != nil { + return + } + _, err = out.Write(content.Bytes()) + if errorutils.CheckError(err) != nil { + return + } + resultsPath = out.Name() + return +} diff --git a/utils/results/output/securityJobSummary.go b/utils/results/output/securityJobSummary.go index 1771090a..e78e1f36 100644 --- a/utils/results/output/securityJobSummary.go +++ b/utils/results/output/securityJobSummary.go @@ -63,7 +63,7 @@ func SecurityCommandsJobSummary() (js *commandsummary.CommandSummary, err error) return commandsummary.New(&SecurityCommandsSummary{}, "security") } -func CreateCommandSummaryResult(section SecuritySummarySection, cmdResults *results.ScanCommandResults) (ScanCommandSummaryResult, error) { +func CreateCommandSummaryResult(section SecuritySummarySection, cmdResults *results.SecurityCommandResults) (ScanCommandSummaryResult, error) { convertor := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{}) summary, err := convertor.ConvertToSummary(cmdResults) if err != nil { @@ -76,7 +76,7 @@ func CreateCommandSummaryResult(section SecuritySummarySection, cmdResults *resu } // Record the security command output -func RecordSecurityCommandOutput(section SecuritySummarySection, cmdResults *results.ScanCommandResults) (err error) { +func RecordSecurityCommandOutput(section SecuritySummarySection, cmdResults *results.SecurityCommandResults) (err error) { if !commandsummary.ShouldRecordSummary() { return } diff --git a/utils/results/results.go b/utils/results/results.go index 41e42fd6..89945942 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -11,18 +11,18 @@ import ( "github.com/owenrumney/go-sarif/v2/sarif" ) -// ScanCommandResults is a struct that holds the results of a security scan/audit command. -type ScanCommandResults struct { +// SecurityCommandResults is a struct that holds the results of a security scan/audit command. +type SecurityCommandResults struct { // General fields describing the command metadata XrayVersion string `json:"xray_version"` EntitledForJas bool `json:"jas_entitled"` // MultiScanId is a unique identifier that is used to group multiple scans together. MultiScanId string `json:"multi_scan_id,omitempty"` // Results for each target in the command - Scans []*ScanResults `json:"scans"` - scansMutex sync.Mutex `json:"-"` + Targets []*TargetResults `json:"targets"` + scansMutex sync.Mutex `json:"-"` // Error that occurred during the command execution - Errors error `json:"errors,omitempty"` + Error error `json:"error,omitempty"` } type ScanTarget struct { @@ -34,19 +34,23 @@ type ScanTarget struct { Technology techutils.Technology `json:"technology,omitempty"` } -type ScanResults struct { +type TargetResults struct { ScanTarget // All scan results for the target - ScaResults []*ScaScanResults `json:"sca_scans,omitempty"` - JasResults *JasScansResults `json:"jas_scans,omitempty"` - // Scan result error - Error error `json:"errors,omitempty"` + ScaResults *ScaScanResults `json:"sca_scans,omitempty"` + JasResults *JasScansResults `json:"jas_scans,omitempty"` + // Errors that occurred during the scans + Errors []error `json:"errors,omitempty"` + // TODO: move to funcs... + errorsMutex sync.Mutex `json:"-"` } type ScaScanResults struct { + IsMultipleRootProject *bool `json:"is_multiple_root_project,omitempty"` + // Target of the scan Descriptors []string `json:"descriptors,omitempty"` // Sca scan results - XrayResult services.ScanResponse `json:"xray_scan"` + XrayResults []services.ScanResponse `json:"xray_scan"` } type JasScansResults struct { @@ -56,37 +60,37 @@ type JasScansResults struct { SastScanResults []*sarif.Run `json:"sast,omitempty"` } -func NewCommandResults(xrayVersion string, entitledForJas bool) *ScanCommandResults { - return &ScanCommandResults{XrayVersion: xrayVersion, EntitledForJas: entitledForJas, scansMutex: sync.Mutex{}} +func NewCommandResults(xrayVersion string, entitledForJas bool) *SecurityCommandResults { + return &SecurityCommandResults{XrayVersion: xrayVersion, EntitledForJas: entitledForJas, scansMutex: sync.Mutex{}} } -func (r *ScanCommandResults) SetMultiScanId(multiScanId string) *ScanCommandResults { +func (r *SecurityCommandResults) SetMultiScanId(multiScanId string) *SecurityCommandResults { r.MultiScanId = multiScanId return r } // --- Aggregated results for all targets --- -func (r *ScanCommandResults) GetScaScansXrayResults() (results []services.ScanResponse) { - for _, scan := range r.Scans { +func (r *SecurityCommandResults) GetScaScansXrayResults() (results []services.ScanResponse) { + for _, scan := range r.Targets { results = append(results, scan.GetScaScansXrayResults()...) } return } -func (r *ScanCommandResults) GetJasScansResults(scanType jasutils.JasScanType) (results []*sarif.Run) { +func (r *SecurityCommandResults) GetJasScansResults(scanType jasutils.JasScanType) (results []*sarif.Run) { if !r.EntitledForJas { return } - for _, scan := range r.Scans { + for _, scan := range r.Targets { results = append(results, scan.GetJasScansResults(scanType)...) } return } -func (r *ScanCommandResults) GetErrors() (err error) { +func (r *SecurityCommandResults) GetErrors() (err error) { err = r.Errors - for _, scan := range r.Scans { + for _, scan := range r.Targets { if scan.Error != nil { err = errors.Join(err, scan.Error) } @@ -94,8 +98,8 @@ func (r *ScanCommandResults) GetErrors() (err error) { return } -func (r *ScanCommandResults) GetTechnologyScaScans(technology techutils.Technology) (scans []*ScaScanResults) { - for _, scan := range r.Scans { +func (r *SecurityCommandResults) GetTechnologyScaScans(technology techutils.Technology) (scans []*ScaScanResults) { + for _, scan := range r.Targets { for _, scaResult := range scan.ScaResults { if scaResult.Technology == technology { scans = append(scans, scaResult) @@ -105,9 +109,9 @@ func (r *ScanCommandResults) GetTechnologyScaScans(technology techutils.Technolo return } -func (r *ScanCommandResults) GetTechnologies() []techutils.Technology { +func (r *SecurityCommandResults) GetTechnologies() []techutils.Technology { technologies := datastructures.MakeSet[techutils.Technology]() - for _, scan := range r.Scans { + for _, scan := range r.Targets { technologies.AddElements(scan.GetTechnologies()...) } return technologies.ToSlice() @@ -115,11 +119,11 @@ func (r *ScanCommandResults) GetTechnologies() []techutils.Technology { // In case multipleRoots is true, the field Component will show the root of each impact path, otherwise it will show the root's child. // Set multipleRoots to true in case the given vulnerabilities array contains (or may contain) results of several projects or files (like in binary scan). -func (r *ScanCommandResults) HasMultipleTargets() bool { - if len(r.Scans) > 1 { +func (r *SecurityCommandResults) HasMultipleTargets() bool { + if len(r.Targets) > 1 { return true } - for _, scan := range r.Scans { + for _, scan := range r.Targets { // If there is more than one SCA scan target (i.e multiple files with dependencies information) if len(scan.ScaResults) > 1 { return true @@ -128,8 +132,8 @@ func (r *ScanCommandResults) HasMultipleTargets() bool { return false } -func (r *ScanCommandResults) HasInformation() bool { - for _, scan := range r.Scans { +func (r *SecurityCommandResults) HasInformation() bool { + for _, scan := range r.Targets { if scan.HasInformation() { return true } @@ -137,8 +141,8 @@ func (r *ScanCommandResults) HasInformation() bool { return false } -func (r *ScanCommandResults) HasFindings() bool { - for _, scan := range r.Scans { +func (r *SecurityCommandResults) HasFindings() bool { + for _, scan := range r.Targets { if scan.HasFindings() { return true } @@ -148,25 +152,25 @@ func (r *ScanCommandResults) HasFindings() bool { // --- Scan on a target --- -func (r *ScanCommandResults) NewScanResults(target ScanTarget) *ScanResults { - scanResults := &ScanResults{ScanTarget: target} +func (r *SecurityCommandResults) NewScanResults(target ScanTarget) *TargetResults { + scanResults := &TargetResults{ScanTarget: target, errorsMutex: sync.Mutex{}} if r.EntitledForJas { scanResults.JasResults = &JasScansResults{} } r.scansMutex.Lock() - r.Scans = append(r.Scans, scanResults) + r.Targets = append(r.Targets, scanResults) r.scansMutex.Unlock() return scanResults } -func (sr *ScanResults) GetScaScansXrayResults() (results []services.ScanResponse) { +func (sr *TargetResults) GetScaScansXrayResults() (results []services.ScanResponse) { for _, scaResult := range sr.ScaResults { results = append(results, scaResult.XrayResult) } return } -func (sr *ScanResults) GetTechnologies() []techutils.Technology { +func (sr *TargetResults) GetTechnologies() []techutils.Technology { technologies := datastructures.MakeSet[techutils.Technology]() for _, scaResult := range sr.ScaResults { technologies.Add(scaResult.Technology) @@ -174,14 +178,14 @@ func (sr *ScanResults) GetTechnologies() []techutils.Technology { return technologies.ToSlice() } -func (sr *ScanResults) GetJasScansResults(scanType jasutils.JasScanType) (results []*sarif.Run) { +func (sr *TargetResults) GetJasScansResults(scanType jasutils.JasScanType) (results []*sarif.Run) { if sr.JasResults == nil { return } return sr.JasResults.GetResults(scanType) } -func (sr *ScanResults) HasInformation() bool { +func (sr *TargetResults) HasInformation() bool { for _, scaResult := range sr.ScaResults { if scaResult.HasInformation() { return true @@ -190,7 +194,7 @@ func (sr *ScanResults) HasInformation() bool { return false } -func (sr *ScanResults) HasFindings() bool { +func (sr *TargetResults) HasFindings() bool { for _, scaResult := range sr.ScaResults { if scaResult.HasFindings() { return true @@ -199,14 +203,28 @@ func (sr *ScanResults) HasFindings() bool { return false } -func (sr *ScanResults) NewScaScanResults(response *services.ScanResponse) *ScaScanResults { +func (sr *TargetResults) AddError(err error) { + sr.errorsMutex.Lock() + sr.Error = errors.Join(sr.Error, err) + sr.errorsMutex.Unlock() +} + +func (sr *TargetResults) SetDescriptors(descriptors ...string) *TargetResults { + if sr.ScaResults == nil { + return sr + } + sr.ScaResults.Descriptors = descriptors + return sr +} + +func (sr *TargetResults) NewScaScanResults(responses ...*services.ScanResponse) *ScaScanResults { scaScanResults := NewScaScanResults(response) sr.ScaResults = append(sr.ScaResults, scaScanResults) return scaScanResults } -func (sr *ScanResults) NewScaScan(target string, technology techutils.Technology) *ScaScanResults { - scaScanResults := &ScaScanResults{ScanTarget: ScanTarget{Target: target, Technology: technology}} +func (sr *TargetResults) NewScaScan(descriptors ...string) *ScaScanResults { + scaScanResults := &ScaScanResults{Descriptors: descriptors} sr.ScaResults = append(sr.ScaResults, scaScanResults) return scaScanResults } diff --git a/utils/results/results_test.go b/utils/results/results_test.go index 38b4fc3c..cc5bc803 100644 --- a/utils/results/results_test.go +++ b/utils/results/results_test.go @@ -15,13 +15,13 @@ func TestGetScaScanResultByTarget(t *testing.T) { target2 := &ScaScanResult{Target: "target2"} testCases := []struct { name string - cmdResults ScanCommandResults + cmdResults SecurityCommandResults target string expected *ScaScanResult }{ { name: "Sca scan result by target", - cmdResults: ScanCommandResults{ + cmdResults: SecurityCommandResults{ ScaResults: []*ScaScanResult{ target1, target2, @@ -32,7 +32,7 @@ func TestGetScaScanResultByTarget(t *testing.T) { }, { name: "Sca scan result by target not found", - cmdResults: ScanCommandResults{ + cmdResults: SecurityCommandResults{ ScaResults: []*ScaScanResult{ target1, target2, @@ -74,21 +74,21 @@ func TestGetSummary(t *testing.T) { testCases := []struct { name string - cmdResults ScanCommandResults + cmdResults SecurityCommandResults expected formats.SummaryResults findingCount int issueCount int }{ { name: "Empty results", - cmdResults: ScanCommandResults{ScaResults: []*ScaScanResult{}}, + cmdResults: SecurityCommandResults{ScaResults: []*ScaScanResult{}}, expected: formats.SummaryResults{Scans: []formats.ScanSummaryResult{{}}}, findingCount: 0, issueCount: 0, }, { name: "One module result", - cmdResults: ScanCommandResults{ + cmdResults: SecurityCommandResults{ ScaResults: []*ScaScanResult{{ Target: "target1", XrayResults: getDummyScaTestResults(true, false), @@ -119,7 +119,7 @@ func TestGetSummary(t *testing.T) { }, { name: "Multiple module results", - cmdResults: ScanCommandResults{ + cmdResults: SecurityCommandResults{ ScaResults: []*ScaScanResult{ { Target: "target1", diff --git a/utils/resultwriter.go b/utils/resultwriter.go index 115b3832..3bb8ebbf 100644 --- a/utils/resultwriter.go +++ b/utils/resultwriter.go @@ -29,7 +29,7 @@ const maxPossibleCve = 10.0 type ResultsWriter struct { // The scan cmdResults. - cmdResults *results.ScanCommandResults + cmdResults *results.SecurityCommandResults // SimpleJsonError Errors to be added to output of the SimpleJson format. simpleJsonError []formats.SimpleJsonError // Format The output format. @@ -50,7 +50,7 @@ type ResultsWriter struct { messages []string } -func NewResultsWriter(scanResults *results.ScanCommandResults) *ResultsWriter { +func NewResultsWriter(scanResults *results.SecurityCommandResults) *ResultsWriter { return &ResultsWriter{cmdResults: scanResults} } @@ -180,7 +180,7 @@ func printMessage(message string) { log.Output("💬" + message) } -func GenereateSarifReportFromResults(cmdResults *results.ScanCommandResults, isMultipleRoots, includeLicenses bool, allowedLicenses []string) (report *sarif.Report, err error) { +func GenereateSarifReportFromResults(cmdResults *results.SecurityCommandResults, isMultipleRoots, includeLicenses bool, allowedLicenses []string) (report *sarif.Report, err error) { report, err = sarifutils.NewReport() if err != nil { return @@ -199,7 +199,7 @@ func GenereateSarifReportFromResults(cmdResults *results.ScanCommandResults, isM return } -func convertXrayResponsesToSarifRun(cmdResults *results.ScanCommandResults, isMultipleRoots, includeLicenses bool, allowedLicenses []string) (run *sarif.Run, err error) { +func convertXrayResponsesToSarifRun(cmdResults *results.SecurityCommandResults, isMultipleRoots, includeLicenses bool, allowedLicenses []string) (run *sarif.Run, err error) { xrayJson, err := ConvertXrayScanToSimpleJson(cmdResults, isMultipleRoots, includeLicenses, true, allowedLicenses) if err != nil { return @@ -353,7 +353,7 @@ func addXrayRule(ruleId, ruleDescription, maxCveScore, summary, markdownDescript }) } -func ConvertXrayScanToSimpleJson(cmdResults *results.ScanCommandResults, isMultipleRoots, includeLicenses, simplifiedOutput bool, allowedLicenses []string) (formats.SimpleJsonResults, error) { +func ConvertXrayScanToSimpleJson(cmdResults *results.SecurityCommandResults, isMultipleRoots, includeLicenses, simplifiedOutput bool, allowedLicenses []string) (formats.SimpleJsonResults, error) { violations, vulnerabilities, licenses := SplitScanResults(cmdResults.ScaResults) jsonTable := formats.SimpleJsonResults{} if len(vulnerabilities) > 0 { @@ -514,7 +514,7 @@ func SplitScanResults(results []*results.ScaScanResult) ([]services.Violation, [ return violations, vulnerabilities, licenses } -func writeJsonResults(cmdResults *results.ScanCommandResults) (resultsPath string, err error) { +func writeJsonResults(cmdResults *results.SecurityCommandResults) (resultsPath string, err error) { out, err := fileutils.CreateTempFile() if errorutils.CheckError(err) != nil { return @@ -551,7 +551,7 @@ func PrintJson(output interface{}) error { return nil } -func PrintSarif(cmdResults *results.ScanCommandResults, isMultipleRoots, includeLicenses bool) error { +func PrintSarif(cmdResults *results.SecurityCommandResults, isMultipleRoots, includeLicenses bool) error { sarifReport, err := GenereateSarifReportFromResults(cmdResults, isMultipleRoots, includeLicenses, nil) if err != nil { return err diff --git a/utils/xsc/analyticsmetrics.go b/utils/xsc/analyticsmetrics.go index e60d66f0..5f45eccd 100644 --- a/utils/xsc/analyticsmetrics.go +++ b/utils/xsc/analyticsmetrics.go @@ -158,7 +158,7 @@ func (ams *AnalyticsMetricsService) GetGeneralEvent(msi string) (*xscservices.Xs return event, err } -func (ams *AnalyticsMetricsService) CreateXscAnalyticsGeneralEventFinalizeFromAuditResults(auditResults *results.ScanCommandResults) *xscservices.XscAnalyticsGeneralEventFinalize { +func (ams *AnalyticsMetricsService) CreateXscAnalyticsGeneralEventFinalizeFromAuditResults(auditResults *results.SecurityCommandResults) *xscservices.XscAnalyticsGeneralEventFinalize { totalDuration := time.Since(ams.GetStartTime()) eventStatus := xscservices.Completed if auditResults.GetErrors() != nil { diff --git a/utils/xsc/analyticsmetrics_test.go b/utils/xsc/analyticsmetrics_test.go index 0ecf53a7..e9b3fb12 100644 --- a/utils/xsc/analyticsmetrics_test.go +++ b/utils/xsc/analyticsmetrics_test.go @@ -80,13 +80,13 @@ func TestAnalyticsMetricsService_createAuditResultsFromXscAnalyticsBasicGeneralE testStruct := []struct { name string - auditResults *results.ScanCommandResults + auditResults *results.SecurityCommandResults want xscservices.XscAnalyticsBasicGeneralEvent }{ - {name: "No audit results", auditResults: &results.ScanCommandResults{}, want: xscservices.XscAnalyticsBasicGeneralEvent{EventStatus: xscservices.Completed}}, + {name: "No audit results", auditResults: &results.SecurityCommandResults{}, want: xscservices.XscAnalyticsBasicGeneralEvent{EventStatus: xscservices.Completed}}, {name: "Valid audit result", auditResults: getDummyContentForGeneralEvent(true, false), want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 7, EventStatus: xscservices.Completed}}, {name: "Scan failed with findings.", auditResults: getDummyContentForGeneralEvent(false, true), want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 1, EventStatus: xscservices.Failed}}, - {name: "Scan failed no findings.", auditResults: &results.ScanCommandResults{Scans: []*results.ScanResults{{Error: errors.New("an error")}}}, want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 0, EventStatus: xscservices.Failed}}, + {name: "Scan failed no findings.", auditResults: &results.SecurityCommandResults{Targets: []*results.TargetResults{{Error: errors.New("an error")}}}, want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 0, EventStatus: xscservices.Failed}}, } mockServer, serverDetails := utils.XscServer(t, xscservices.AnalyticsMetricsMinXscVersion) defer mockServer.Close() @@ -105,7 +105,7 @@ func TestAnalyticsMetricsService_createAuditResultsFromXscAnalyticsBasicGeneralE } } -func getDummyContentForGeneralEvent(withJas, withErr bool) *results.ScanCommandResults { +func getDummyContentForGeneralEvent(withJas, withErr bool) *results.SecurityCommandResults { vulnerabilities := []services.Vulnerability{{IssueId: "XRAY-ID", Cves: []services.Cve{{Id: "CVE-123"}}, Components: map[string]services.Component{"issueId_2_direct_dependency": {}}}} cmdResults := results.NewCommandResults("", true) From 77b3ab24f7f6122ba06812a495613f66c4adf5a2 Mon Sep 17 00:00:00 2001 From: attiasas Date: Wed, 3 Jul 2024 09:13:57 +0300 Subject: [PATCH 09/82] finish comp errors --- commands/audit/audit.go | 8 +- commands/audit/audit_test.go | 41 +- commands/audit/sca/npm/npm.go | 7 +- commands/audit/sca/npm/npm_test.go | 3 +- commands/audit/sca/pnpm/pnpm.go | 3 +- commands/audit/sca/yarn/yarn.go | 3 +- commands/audit/sca/yarn/yarn_test.go | 29 +- commands/audit/scarunner_test.go | 1 - commands/curation/curationaudit.go | 3 +- commands/scan/buildscan.go | 3 +- commands/scan/scan.go | 6 +- jas/common.go | 6 +- utils/jasutils/jasutils.go | 4 + utils/results/common.go | 15 +- utils/results/conversion/convertor.go | 126 +- .../conversion/sarifparser/sarifparser.go | 2 +- .../simplejsonparser/simplejsonparser.go | 8 +- .../conversion/summaryparser/summaryparser.go | 2 +- .../conversion/tableparser/tableparser.go | 4 +- utils/results/output/resultwriter.go | 59 +- utils/results/results.go | 319 ++--- utils/results/results_test.go | 388 +++--- utils/resultstable.go | 967 -------------- utils/resultstable_test.go | 1111 ----------------- utils/resultwriter.go | 589 --------- utils/resultwriter_test.go | 406 ------ utils/techutils/techutils.go | 12 +- utils/xsc/analyticsmetrics_test.go | 4 +- 28 files changed, 519 insertions(+), 3610 deletions(-) delete mode 100644 utils/resultstable.go delete mode 100644 utils/resultstable_test.go delete mode 100644 utils/resultwriter.go delete mode 100644 utils/resultwriter_test.go diff --git a/commands/audit/audit.go b/commands/audit/audit.go index ae08a246..ebe34fb5 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -13,6 +13,7 @@ import ( "github.com/jfrog/jfrog-cli-security/jas/runner" "github.com/jfrog/jfrog-cli-security/jas/secrets" "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/results/output" "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-cli-security/utils/xray/scangraph" "github.com/jfrog/jfrog-cli-security/utils/xsc" @@ -152,8 +153,7 @@ func (auditCmd *AuditCommand) Run() (err error) { if !auditResults.EntitledForJas { messages = []string{coreutils.PrintTitle("The ‘jf audit’ command also supports JFrog Advanced Security features, such as 'Contextual Analysis', 'Secret Detection', 'IaC Scan' and ‘SAST’.\nThis feature isn't enabled on your system. Read more - ") + coreutils.PrintLink("https://jfrog.com/xray/")} } - if err = utils.NewResultsWriter(auditResults). - SetIsMultipleRootProject(auditResults.HasMultipleTargets()). + if err = output.NewResultsWriter(auditResults). SetIncludeVulnerabilities(auditCmd.IncludeVulnerabilities). SetIncludeLicenses(auditCmd.IncludeLicenses). SetOutputFormat(auditCmd.OutputFormat()). @@ -170,8 +170,8 @@ func (auditCmd *AuditCommand) Run() (err error) { } // Only in case Xray's context was given (!auditCmd.IncludeVulnerabilities), and the user asked to fail the build accordingly, do so. - if auditCmd.Fail && !auditCmd.IncludeVulnerabilities && utils.CheckIfFailBuild(auditResults.GetScaScansXrayResults()) { - err = utils.NewFailBuildError() + if auditCmd.Fail && !auditCmd.IncludeVulnerabilities && results.CheckIfFailBuild(auditResults.GetScaScansXrayResults()) { + err = results.NewFailBuildError() } return } diff --git a/commands/audit/audit_test.go b/commands/audit/audit_test.go index 8680b1e7..766500bc 100644 --- a/commands/audit/audit_test.go +++ b/commands/audit/audit_test.go @@ -10,7 +10,6 @@ import ( "github.com/stretchr/testify/assert" ) - func TestDetectScansToPreform(t *testing.T) { dir, cleanUp := createTestDir(t) @@ -37,16 +36,16 @@ func TestDetectScansToPreform(t *testing.T) { }, ScaResults: &results.ScaScanResults{ Descriptors: []string{ - filepath.Join(dir, "dir", "maven", "pom.xml"), - filepath.Join(dir, "dir", "maven", "maven-sub", "pom.xml"), - filepath.Join(dir, "dir", "maven", "maven-sub2", "pom.xml"), + filepath.Join(dir, "dir", "maven", "pom.xml"), + filepath.Join(dir, "dir", "maven", "maven-sub", "pom.xml"), + filepath.Join(dir, "dir", "maven", "maven-sub2", "pom.xml"), }, }, }, { ScanTarget: results.ScanTarget{ - Technology: techutils.Npm, - Target: filepath.Join(dir, "dir", "npm"), + Technology: techutils.Npm, + Target: filepath.Join(dir, "dir", "npm"), }, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "dir", "npm", "package.json")}, @@ -54,8 +53,8 @@ func TestDetectScansToPreform(t *testing.T) { }, { ScanTarget: results.ScanTarget{ - Technology: techutils.Go, - Target: filepath.Join(dir, "dir", "go"), + Technology: techutils.Go, + Target: filepath.Join(dir, "dir", "go"), }, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "dir", "go", "go.mod")}, @@ -87,8 +86,8 @@ func TestDetectScansToPreform(t *testing.T) { }, { ScanTarget: results.ScanTarget{ - Technology: techutils.Npm, - Target: filepath.Join(dir, "dir", "npm"), + Technology: techutils.Npm, + Target: filepath.Join(dir, "dir", "npm"), }, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "dir", "npm", "package.json")}, @@ -96,8 +95,8 @@ func TestDetectScansToPreform(t *testing.T) { }, { ScanTarget: results.ScanTarget{ - Technology: techutils.Go, - Target: filepath.Join(dir, "dir", "go"), + Technology: techutils.Go, + Target: filepath.Join(dir, "dir", "go"), }, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "dir", "go", "go.mod")}, @@ -105,8 +104,8 @@ func TestDetectScansToPreform(t *testing.T) { }, { ScanTarget: results.ScanTarget{ - Technology: techutils.Yarn, - Target: filepath.Join(dir, "yarn"), + Technology: techutils.Yarn, + Target: filepath.Join(dir, "yarn"), }, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "yarn", "package.json")}, @@ -114,8 +113,8 @@ func TestDetectScansToPreform(t *testing.T) { }, { ScanTarget: results.ScanTarget{ - Technology: techutils.Pip, - Target: filepath.Join(dir, "yarn", "Pip"), + Technology: techutils.Pip, + Target: filepath.Join(dir, "yarn", "Pip"), }, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "yarn", "Pip", "requirements.txt")}, @@ -123,8 +122,8 @@ func TestDetectScansToPreform(t *testing.T) { }, { ScanTarget: results.ScanTarget{ - Technology: techutils.Pipenv, - Target: filepath.Join(dir, "yarn", "Pipenv"), + Technology: techutils.Pipenv, + Target: filepath.Join(dir, "yarn", "Pipenv"), }, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "yarn", "Pipenv", "Pipfile")}, @@ -132,8 +131,8 @@ func TestDetectScansToPreform(t *testing.T) { }, { ScanTarget: results.ScanTarget{ - Technology: techutils.Nuget, - Target: filepath.Join(dir, "Nuget"), + Technology: techutils.Nuget, + Target: filepath.Join(dir, "Nuget"), }, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "Nuget", "project.sln"), filepath.Join(dir, "Nuget", "Nuget-sub", "project.csproj")}, @@ -158,4 +157,4 @@ func TestDetectScansToPreform(t *testing.T) { } cleanUp() -} \ No newline at end of file +} diff --git a/commands/audit/sca/npm/npm.go b/commands/audit/sca/npm/npm.go index e596f37d..a04a8844 100644 --- a/commands/audit/sca/npm/npm.go +++ b/commands/audit/sca/npm/npm.go @@ -9,6 +9,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/npm" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-cli-security/utils/xray" "github.com/jfrog/jfrog-client-go/utils/log" xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" @@ -108,9 +109,9 @@ func addIgnoreScriptsFlag(npmArgs []string) []string { func parseNpmDependenciesList(dependencies []buildinfo.Dependency, packageInfo *biutils.PackageInfo) (*xrayUtils.GraphNode, []string) { treeMap := make(map[string]xray.DepTreeNode) for _, dependency := range dependencies { - dependencyId := utils.NpmPackageTypeIdentifier + dependency.Id + dependencyId := techutils.Npm.GetPackageTypeId() + dependency.Id for _, requestedByNode := range dependency.RequestedBy { - parent := utils.NpmPackageTypeIdentifier + requestedByNode[0] + parent := techutils.Npm.GetPackageTypeId() + requestedByNode[0] depTreeNode, ok := treeMap[parent] if ok { depTreeNode.Children = appendUniqueChild(depTreeNode.Children, dependencyId) @@ -120,7 +121,7 @@ func parseNpmDependenciesList(dependencies []buildinfo.Dependency, packageInfo * treeMap[parent] = depTreeNode } } - graph, nodeMapTypes := xray.BuildXrayDependencyTree(treeMap, utils.NpmPackageTypeIdentifier+packageInfo.BuildInfoModuleId()) + graph, nodeMapTypes := xray.BuildXrayDependencyTree(treeMap, techutils.Npm.GetPackageTypeId()+packageInfo.BuildInfoModuleId()) return graph, maps.Keys(nodeMapTypes) } diff --git a/commands/audit/sca/npm/npm_test.go b/commands/audit/sca/npm/npm_test.go index def8bfe4..d679564c 100644 --- a/commands/audit/sca/npm/npm_test.go +++ b/commands/audit/sca/npm/npm_test.go @@ -8,6 +8,7 @@ import ( "github.com/jfrog/jfrog-cli-security/commands/audit/sca" "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/techutils" xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" biutils "github.com/jfrog/build-info-go/build/utils" @@ -105,7 +106,7 @@ func TestParseNpmDependenciesList(t *testing.T) { } expectedUniqueDeps := []string{xrayDependenciesTree.Id} for _, dep := range dependencies { - expectedUniqueDeps = append(expectedUniqueDeps, utils.NpmPackageTypeIdentifier+dep.Id) + expectedUniqueDeps = append(expectedUniqueDeps, techutils.Npm.GetPackageTypeId()+dep.Id) } assert.ElementsMatch(t, uniqueDeps, expectedUniqueDeps, "First is actual, Second is Expected") diff --git a/commands/audit/sca/pnpm/pnpm.go b/commands/audit/sca/pnpm/pnpm.go index b2197392..de324b2d 100644 --- a/commands/audit/sca/pnpm/pnpm.go +++ b/commands/audit/sca/pnpm/pnpm.go @@ -15,6 +15,7 @@ import ( "github.com/jfrog/jfrog-cli-security/commands/audit/sca/npm" "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-cli-security/utils/xray" "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" @@ -175,7 +176,7 @@ func createProjectDependenciesTree(project pnpmLsProject) map[string]xray.DepTre // Return npm://: of a dependency func getDependencyId(depName, version string) string { - return utils.NpmPackageTypeIdentifier + depName + ":" + version + return techutils.Npm.GetPackageTypeId() + depName + ":" + version } func appendTransitiveDependencies(parent string, dependencies map[string]pnpmLsDependency, result map[string]xray.DepTreeNode) { diff --git a/commands/audit/sca/yarn/yarn.go b/commands/audit/sca/yarn/yarn.go index 2854f778..1d6a20ec 100644 --- a/commands/audit/sca/yarn/yarn.go +++ b/commands/audit/sca/yarn/yarn.go @@ -15,6 +15,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-core/v2/utils/ioutils" "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-cli-security/utils/xray" "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" @@ -217,5 +218,5 @@ func parseYarnDependenciesMap(dependencies map[string]*biutils.YarnDependency, r } func getXrayDependencyId(yarnDependency *biutils.YarnDependency) string { - return utils.NpmPackageTypeIdentifier + yarnDependency.Name() + ":" + yarnDependency.Details.Version + return techutils.Npm.GetPackageTypeId() + yarnDependency.Name() + ":" + yarnDependency.Details.Version } diff --git a/commands/audit/sca/yarn/yarn_test.go b/commands/audit/sca/yarn/yarn_test.go index faad4d64..06b1c385 100644 --- a/commands/audit/sca/yarn/yarn_test.go +++ b/commands/audit/sca/yarn/yarn_test.go @@ -1,16 +1,17 @@ package yarn import ( + "path/filepath" + "testing" + "github.com/jfrog/build-info-go/build" biutils "github.com/jfrog/build-info-go/build/utils" utils2 "github.com/jfrog/build-info-go/utils" "github.com/jfrog/jfrog-cli-core/v2/utils/tests" - "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" "github.com/stretchr/testify/assert" - "path/filepath" - "testing" ) func TestParseYarnDependenciesList(t *testing.T) { @@ -22,30 +23,30 @@ func TestParseYarnDependenciesList(t *testing.T) { "pack5@npm:5.0.0": {Value: "pack5@npm:5.0.0", Details: biutils.YarnDepDetails{Version: "5.0.0", Dependencies: []biutils.YarnDependencyPointer{{Locator: "pack2@npm:2.0.0"}}}}, } - rootXrayId := utils.NpmPackageTypeIdentifier + "@jfrog/pack3:3.0.0" + rootXrayId := techutils.Npm.GetPackageTypeId() + "@jfrog/pack3:3.0.0" expectedTree := &xrayUtils.GraphNode{ Id: rootXrayId, Nodes: []*xrayUtils.GraphNode{ - {Id: utils.NpmPackageTypeIdentifier + "pack1:1.0.0", + {Id: techutils.Npm.GetPackageTypeId() + "pack1:1.0.0", Nodes: []*xrayUtils.GraphNode{ - {Id: utils.NpmPackageTypeIdentifier + "pack4:4.0.0", + {Id: techutils.Npm.GetPackageTypeId() + "pack4:4.0.0", Nodes: []*xrayUtils.GraphNode{}}, }}, - {Id: utils.NpmPackageTypeIdentifier + "pack2:2.0.0", + {Id: techutils.Npm.GetPackageTypeId() + "pack2:2.0.0", Nodes: []*xrayUtils.GraphNode{ - {Id: utils.NpmPackageTypeIdentifier + "pack4:4.0.0", + {Id: techutils.Npm.GetPackageTypeId() + "pack4:4.0.0", Nodes: []*xrayUtils.GraphNode{}}, - {Id: utils.NpmPackageTypeIdentifier + "pack5:5.0.0", + {Id: techutils.Npm.GetPackageTypeId() + "pack5:5.0.0", Nodes: []*xrayUtils.GraphNode{}}, }}, }, } expectedUniqueDeps := []string{ - utils.NpmPackageTypeIdentifier + "pack1:1.0.0", - utils.NpmPackageTypeIdentifier + "pack2:2.0.0", - utils.NpmPackageTypeIdentifier + "pack4:4.0.0", - utils.NpmPackageTypeIdentifier + "pack5:5.0.0", - utils.NpmPackageTypeIdentifier + "@jfrog/pack3:3.0.0", + techutils.Npm.GetPackageTypeId() + "pack1:1.0.0", + techutils.Npm.GetPackageTypeId() + "pack2:2.0.0", + techutils.Npm.GetPackageTypeId() + "pack4:4.0.0", + techutils.Npm.GetPackageTypeId() + "pack5:5.0.0", + techutils.Npm.GetPackageTypeId() + "@jfrog/pack3:3.0.0", } xrayDependenciesTree, uniqueDeps := parseYarnDependenciesMap(yarnDependencies, rootXrayId) diff --git a/commands/audit/scarunner_test.go b/commands/audit/scarunner_test.go index 0dda7c36..09b2fc5f 100644 --- a/commands/audit/scarunner_test.go +++ b/commands/audit/scarunner_test.go @@ -113,4 +113,3 @@ func createEmptyFile(t *testing.T, path string) { assert.NoError(t, err) assert.NoError(t, file.Close()) } - diff --git a/commands/curation/curationaudit.go b/commands/curation/curationaudit.go index eaf48f1a..322cec67 100644 --- a/commands/curation/curationaudit.go +++ b/commands/curation/curationaudit.go @@ -24,6 +24,7 @@ import ( "github.com/jfrog/jfrog-cli-security/commands/audit" "github.com/jfrog/jfrog-cli-security/commands/audit/sca/python" "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/results/output" "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-cli-security/utils/xray" "github.com/jfrog/jfrog-client-go/artifactory" @@ -371,7 +372,7 @@ func printResult(format outFormat.OutputFormat, projectPath string, packagesStat switch format { case outFormat.Json: if len(packagesStatus) > 0 { - err := utils.PrintJson(packagesStatus) + err := output.PrintJson(packagesStatus) if err != nil { return err } diff --git a/commands/scan/buildscan.go b/commands/scan/buildscan.go index 57076f0d..998acc2c 100644 --- a/commands/scan/buildscan.go +++ b/commands/scan/buildscan.go @@ -7,7 +7,6 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/common/build" outputFormat "github.com/jfrog/jfrog-cli-core/v2/common/format" "github.com/jfrog/jfrog-cli-core/v2/utils/config" - "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/results/output" xrayutils "github.com/jfrog/jfrog-cli-security/utils/xray" @@ -133,7 +132,7 @@ func (bsc *BuildScanCommand) runBuildScanAndPrintResults(xrayManager *xray.XrayS XrayDataUrl: buildScanResults.MoreDetailsUrl, }) - resultsPrinter := utils.NewResultsWriter(cmdResults). + resultsPrinter := output.NewResultsWriter(cmdResults). SetOutputFormat(bsc.outputFormat). SetIncludeVulnerabilities(bsc.includeVulnerabilities). SetIncludeLicenses(false). diff --git a/commands/scan/scan.go b/commands/scan/scan.go index b827ecfe..1c0caeb5 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -278,7 +278,7 @@ func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults * err = errors.New("failed while trying to get Analyzer Manager: " + err.Error()) } - if err = utils.NewResultsWriter(cmdResults). + if err = output.NewResultsWriter(cmdResults). SetOutputFormat(scanCmd.outputFormat). SetIncludeVulnerabilities(scanCmd.includeVulnerabilities). SetIncludeLicenses(scanCmd.includeLicenses). @@ -296,8 +296,8 @@ func (scanCmd *ScanCommand) RunAndRecordResults(recordResFunc func(scanResults * // If includeVulnerabilities is false it means that context was provided, so we need to check for build violations. // If user provided --fail=false, don't fail the build. if scanCmd.fail && !scanCmd.includeVulnerabilities { - if utils.CheckIfFailBuild(cmdResults.GetScaScansXrayResults()) { - return utils.NewFailBuildError() + if results.CheckIfFailBuild(cmdResults.GetScaScansXrayResults()) { + return results.NewFailBuildError() } } if cmdResults.GetErrors() != nil { diff --git a/jas/common.go b/jas/common.go index b198dd4b..27d9a7a4 100644 --- a/jas/common.go +++ b/jas/common.go @@ -34,9 +34,9 @@ import ( ) type JasScanner struct { - TempDir string - AnalyzerManager AnalyzerManager - ServerDetails *config.ServerDetails + TempDir string + AnalyzerManager AnalyzerManager + ServerDetails *config.ServerDetails // JFrogAppsConfig *jfrogappsconfig.JFrogAppsConfig ScannerDirCleanupFunc func() error Exclusions []string diff --git a/utils/jasutils/jasutils.go b/utils/jasutils/jasutils.go index abb19ef5..491f1500 100644 --- a/utils/jasutils/jasutils.go +++ b/utils/jasutils/jasutils.go @@ -23,6 +23,10 @@ func (jst JasScanType) String() string { return string(jst) } +func GetJasScanTypes() []JasScanType { + return []JasScanType{Applicability, Secrets, IaC, Sast} +} + type ApplicabilityStatus string const ( diff --git a/utils/results/common.go b/utils/results/common.go index 1655f653..fc5588b6 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -25,7 +25,6 @@ const ( directDependencyIndex = 1 directDependencyPathLength = 2 nodeModules = "node_modules" - NpmPackageTypeIdentifier = "npm://" ) var ( @@ -415,11 +414,11 @@ func SplitScaScanResults(results *SecurityCommandResults) ([]services.Violation, var violations []services.Violation var vulnerabilities []services.Vulnerability var licenses []services.License - for _, scan := range results.Targets { - for _, scaScan := range scan.ScaResults { - violations = append(violations, scaScan.XrayResult.Violations...) - vulnerabilities = append(vulnerabilities, scaScan.XrayResult.Vulnerabilities...) - licenses = append(licenses, scaScan.XrayResult.Licenses...) + for _, scanTarget := range results.Targets { + for _, scaScan := range scanTarget.ScaResults.XrayResults { + violations = append(violations, scaScan.Violations...) + vulnerabilities = append(vulnerabilities, scaScan.Vulnerabilities...) + licenses = append(licenses, scaScan.Licenses...) } } return violations, vulnerabilities, licenses @@ -550,10 +549,10 @@ func getApplicabilityStatusFromRule(rule *sarif.ReportingDescriptor) jasutils.Ap // Found use of a badCode inside the node_modules from a different package, report applicable. func shouldDisqualifyEvidence(components map[string]services.Component, evidenceFilePath string) (disqualify bool) { for key := range components { - if !strings.HasPrefix(key, NpmPackageTypeIdentifier) { + if !strings.HasPrefix(key, techutils.Npm.GetPackageTypeId()) { return } - dependencyName := extractDependencyNameFromComponent(key, NpmPackageTypeIdentifier) + dependencyName := extractDependencyNameFromComponent(key, techutils.Npm.GetPackageTypeId()) // Check both Unix & Windows paths. if strings.Contains(evidenceFilePath, nodeModules+"/"+dependencyName) || strings.Contains(evidenceFilePath, filepath.Join(nodeModules, dependencyName)) { return true diff --git a/utils/results/conversion/convertor.go b/utils/results/conversion/convertor.go index 0e912215..ffe6d496 100644 --- a/utils/results/conversion/convertor.go +++ b/utils/results/conversion/convertor.go @@ -21,6 +21,8 @@ type CommandResultsConvertor struct { } type ResultConvertParams struct { + // Control and override converting command results as multi target results + IsMultipleRoots *bool // Control if the output should include licenses information IncludeLicenses bool // Control if the output should include vulnerabilities information @@ -44,7 +46,7 @@ type ResultsStreamFormatParser interface { // Reset the convertor to start converting a new command results Reset(multiScanId, xrayVersion string, entitledForJas bool) error // Will be called for each scan target (indicating the current is done parsing and starting to parse a new scan) - ParseNewScanResultsMetadata(target string, errors error) error + ParseNewScanResultsMetadata(target string, errors ...error) error // Parse SCA content to the current scan target ParseViolations(target string, tech techutils.Technology, violations []services.Violation, applicabilityRuns ...*sarif.Run) error ParseVulnerabilities(target string, tech techutils.Technology, vulnerabilities []services.Vulnerability, applicabilityRuns ...*sarif.Run) error @@ -106,70 +108,96 @@ func (c *CommandResultsConvertor) ConvertToSummary(cmdResults *results.SecurityC func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormatParser, cmdResults *results.SecurityCommandResults) (err error) { jasEntitled := cmdResults.EntitledForJas multipleTargets := cmdResults.HasMultipleTargets() + if c.Params.IsMultipleRoots != nil { + multipleTargets = *c.Params.IsMultipleRoots + } parser.Reset(cmdResults.MultiScanId, cmdResults.XrayVersion, jasEntitled) - for _, scan := range cmdResults.Targets { - if err = parser.ParseNewScanResultsMetadata(scan.Target, scan.Error); err != nil { - return err + for _, targetScansResults := range cmdResults.Targets { + if err = parser.ParseNewScanResultsMetadata(targetScansResults.Target, targetScansResults.Errors...); err != nil { + return } - for _, scaResults := range scan.ScaResults { - actualTarget := scaResults.Target - if actualTarget == "" { - // If target was not provided, use the scan target - // TODO: make sure works for build-scan since its not a file - actualTarget = scan.Target - } - var applicableRuns []*sarif.Run - if jasEntitled && scan.JasResults != nil { - applicableRuns = scan.JasResults.ApplicabilityScanResults - } - vulnerabilities := scaResults.XrayResult.Vulnerabilities - if c.Params.SimplifiedOutput { - vulnerabilities = simplifyVulnerabilities(vulnerabilities, multipleTargets) - } - if len(vulnerabilities) > 0 { - if err = parser.ParseVulnerabilities(actualTarget, scaResults.Technology, vulnerabilities, applicableRuns...); err != nil { - return - } - } - violations := scaResults.XrayResult.Violations - if c.Params.SimplifiedOutput { - violations = simplifyViolations(violations, multipleTargets) - } - if len(violations) > 0 { - if err = parser.ParseViolations(actualTarget, scaResults.Technology, violations, applicableRuns...); err != nil { - return - } - } else if len(c.Params.AllowedLicenses) > 0 { - // If no violations were found, check if there are licenses that are not allowed - licViolations := results.GetViolatedLicenses(c.Params.AllowedLicenses, scaResults.XrayResult.Licenses) - if len(licViolations) > 0 { - if err = parser.ParseViolations(actualTarget, scaResults.Technology, results.GetViolatedLicenses(c.Params.AllowedLicenses, scaResults.XrayResult.Licenses)); err != nil { - return - } - } - } - if c.Params.IncludeLicenses { - if err = parser.ParseLicenses(actualTarget, scaResults.Technology, scaResults.XrayResult.Licenses); err != nil { - return - } + if targetScansResults.ScaResults != nil { + if err = c.parseScaResults(parser, targetScansResults, jasEntitled, multipleTargets); err != nil { + return } } - if !jasEntitled || scan.JasResults == nil { + if !jasEntitled || targetScansResults.JasResults == nil { continue } - if err = parser.ParseSecrets(scan.Target, scan.JasResults.SecretsScanResults...); err != nil { + if err = parser.ParseSecrets(targetScansResults.Target, targetScansResults.JasResults.SecretsScanResults...); err != nil { return } - if err = parser.ParseIacs(scan.Target, scan.JasResults.IacScanResults...); err != nil { + if err = parser.ParseIacs(targetScansResults.Target, targetScansResults.JasResults.IacScanResults...); err != nil { return } - if err = parser.ParseSast(scan.Target, scan.JasResults.SastScanResults...); err != nil { + if err = parser.ParseSast(targetScansResults.Target, targetScansResults.JasResults.SastScanResults...); err != nil { return } } return } +func (c *CommandResultsConvertor) parseScaResults(parser ResultsStreamFormatParser, targetScansResults *results.TargetResults, jasEntitled, multipleTargets bool) (err error) { + for _, scaResults := range targetScansResults.ScaResults.XrayResults { + actualTarget := getScaScanTarget(targetScansResults.ScaResults, targetScansResults.Target) + var applicableRuns []*sarif.Run + if jasEntitled && targetScansResults.JasResults != nil { + applicableRuns = targetScansResults.JasResults.ApplicabilityScanResults + } + vulnerabilities := scaResults.Vulnerabilities + if c.Params.SimplifiedOutput { + vulnerabilities = simplifyVulnerabilities(vulnerabilities, multipleTargets) + } + if len(vulnerabilities) > 0 { + if err = parser.ParseVulnerabilities(actualTarget, targetScansResults.Technology, vulnerabilities, applicableRuns...); err != nil { + return + } + } + violations := scaResults.Violations + if c.Params.SimplifiedOutput { + violations = simplifyViolations(violations, multipleTargets) + } + if len(violations) > 0 { + if err = parser.ParseViolations(actualTarget, targetScansResults.Technology, violations, applicableRuns...); err != nil { + return + } + } else if len(c.Params.AllowedLicenses) > 0 { + // If no violations were found, check if there are licenses that are not allowed + licViolations := results.GetViolatedLicenses(c.Params.AllowedLicenses, scaResults.Licenses) + if len(licViolations) > 0 { + if err = parser.ParseViolations(actualTarget, targetScansResults.Technology, results.GetViolatedLicenses(c.Params.AllowedLicenses, scaResults.Licenses)); err != nil { + return + } + } + } + if c.Params.IncludeLicenses { + if err = parser.ParseLicenses(actualTarget, targetScansResults.Technology, scaResults.Licenses); err != nil { + return + } + } + } + return +} + +func getScaScanTarget(scaResults *results.ScaScanResults, target string) string { + if scaResults == nil || len(scaResults.Descriptors) == 0 { + // If target was not provided, use the scan target + // TODO: make sure works for build-scan since its not a file + return target + } + // Get the one that it's directory is the prefix of the target and the shortest + var bestMatch string + for _, descriptor := range scaResults.Descriptors { + if strings.HasPrefix(descriptor, target) && (bestMatch == "" || len(descriptor) < len(bestMatch)) { + bestMatch = descriptor + } + } + if bestMatch != "" { + return bestMatch + } + return target +} + // simplifyViolations returns a new slice of services.Violations that contains only the unique violations from the input slice // The uniqueness of the violations is determined by the GetUniqueKey function func simplifyViolations(scanViolations []services.Violation, multipleRoots bool) []services.Violation { diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index f9aa478c..f54d94e1 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -61,7 +61,7 @@ func (sc *CmdResultsSarifConverter) Reset(_, xrayVersion string, entitledForJas return } -func (sc *CmdResultsSarifConverter) ParseNewScanResultsMetadata(target string, errors error) (err error) { +func (sc *CmdResultsSarifConverter) ParseNewScanResultsMetadata(target string, _ ...error) (err error) { if sc.current == nil { return results.ConvertorResetErr } diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go index 1427f6fa..9adb04ff 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go @@ -41,12 +41,14 @@ func (sjc *CmdResultsSimpleJsonConverter) Reset(multiScanId, _ string, entitledF return } -func (sjc *CmdResultsSimpleJsonConverter) ParseNewScanResultsMetadata(target string, errors error) (err error) { +func (sjc *CmdResultsSimpleJsonConverter) ParseNewScanResultsMetadata(target string, errors ...error) (err error) { if sjc.current == nil { return results.ConvertorResetErr } - if errors != nil { - sjc.current.Errors = append(sjc.current.Errors, formats.SimpleJsonError{FilePath: target, ErrorMessage: errors.Error()}) + for _, err := range errors { + if err != nil { + sjc.current.Errors = append(sjc.current.Errors, formats.SimpleJsonError{FilePath: target, ErrorMessage: err.Error()}) + } } return } diff --git a/utils/results/conversion/summaryparser/summaryparser.go b/utils/results/conversion/summaryparser/summaryparser.go index b3b08983..135b9805 100644 --- a/utils/results/conversion/summaryparser/summaryparser.go +++ b/utils/results/conversion/summaryparser/summaryparser.go @@ -38,7 +38,7 @@ func (sc *CmdResultsSummaryConverter) Reset(_, _ string, entitledForJas bool) (e return } -func (sc *CmdResultsSummaryConverter) ParseNewScanResultsMetadata(target string, errors error) (err error) { +func (sc *CmdResultsSummaryConverter) ParseNewScanResultsMetadata(target string, _ ...error) (err error) { if sc.current == nil { return results.ConvertorResetErr } diff --git a/utils/results/conversion/tableparser/tableparser.go b/utils/results/conversion/tableparser/tableparser.go index 5d479d85..be7f1af8 100644 --- a/utils/results/conversion/tableparser/tableparser.go +++ b/utils/results/conversion/tableparser/tableparser.go @@ -39,8 +39,8 @@ func (tc *CmdResultsTableConverter) Reset(multiScanId, xrayVersion string, entit return tc.simpleJsonConvertor.Reset(multiScanId, xrayVersion, entitledForJas) } -func (tc *CmdResultsTableConverter) ParseNewScanResultsMetadata(target string, errors error) (err error) { - return tc.simpleJsonConvertor.ParseNewScanResultsMetadata(target, errors) +func (tc *CmdResultsTableConverter) ParseNewScanResultsMetadata(target string, errors ...error) (err error) { + return tc.simpleJsonConvertor.ParseNewScanResultsMetadata(target, errors...) } func (tc *CmdResultsTableConverter) ParseViolations(target string, tech techutils.Technology, violations []services.Violation, applicabilityRuns ...*sarif.Run) (err error) { diff --git a/utils/results/output/resultwriter.go b/utils/results/output/resultwriter.go index 81f9958b..46d457a5 100644 --- a/utils/results/output/resultwriter.go +++ b/utils/results/output/resultwriter.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "os" + "slices" "github.com/jfrog/jfrog-cli-core/v2/common/format" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" @@ -28,10 +29,14 @@ type ResultsWriter struct { includeVulnerabilities bool // IncludeLicenses If true, also include license violations as part of the output. includeLicenses bool + // IsMultipleRoots multipleRoots is set to true, in case the given results array contains (or may contain) results of several projects (like in binary scan). + isMultipleRoots *bool // PrintExtended, If true, show extended results. printExtended bool // The scanType (binary,dependency) scanType services.ScanType + // For table format - show table only for the given subScansPreformed + subScansPreformed []utils.SubScanType // Messages - Option array of messages, to be displayed if the format is Table messages []string } @@ -45,11 +50,21 @@ func (rw *ResultsWriter) SetOutputFormat(f format.OutputFormat) *ResultsWriter { return rw } +func (rw *ResultsWriter) SetIsMultipleRootProject(isMultipleRootProject bool) *ResultsWriter { + rw.isMultipleRoots = &isMultipleRootProject + return rw +} + func (rw *ResultsWriter) SetScanType(scanType services.ScanType) *ResultsWriter { rw.scanType = scanType return rw } +func (rw *ResultsWriter) SetSubScansPreformed(subScansPreformed []utils.SubScanType) *ResultsWriter { + rw.subScansPreformed = subScansPreformed + return rw +} + func (rw *ResultsWriter) SetIncludeVulnerabilities(includeVulnerabilities bool) *ResultsWriter { rw.includeVulnerabilities = includeVulnerabilities return rw @@ -87,6 +102,13 @@ func isPrettyOutputSupported() bool { return log.IsStdOutTerminal() && log.IsColorsSupported() || os.Getenv("GITLAB_CI") != "" } +func shouldPrintTable(requestedScans []utils.SubScanType, subScan utils.SubScanType, scanType services.ScanType) bool { + if scanType == services.Binary && (subScan == utils.IacScan || subScan == utils.SastScan) { + return false + } + return len(requestedScans) == 0 || slices.Contains(requestedScans, subScan) +} + // PrintScanResults prints the scan results in the specified format. // Note that errors are printed only with SimpleJson format. func (rw *ResultsWriter) PrintScanResults() error { @@ -116,6 +138,7 @@ func (rw *ResultsWriter) PrintScanResults() error { func (rw *ResultsWriter) createResultsConvertor(pretty bool) *conversion.CommandResultsConvertor { return conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{ + IsMultipleRoots: rw.isMultipleRoots, IncludeLicenses: rw.includeLicenses, IncludeVulnerabilities: rw.includeVulnerabilities, Pretty: pretty, @@ -159,24 +182,34 @@ func (rw *ResultsWriter) printTables() (err error) { printMessage(coreutils.PrintTitle("The full scan results are available here: ") + coreutils.PrintLink(resultsPath)) } log.Output() - if rw.includeVulnerabilities { - err = PrintVulnerabilitiesTable(tableContent, rw.scanType, len(rw.commandResults.GetTechnologies()) > 0, rw.printExtended) - } else { - err = PrintViolationsTable(tableContent, rw.scanType, rw.printExtended) - } - if err != nil { - return + + if shouldPrintTable(rw.subScansPreformed, utils.ScaScan, rw.scanType) { + if rw.includeVulnerabilities { + err = PrintVulnerabilitiesTable(tableContent, rw.scanType, len(rw.commandResults.GetTechnologies()) > 0, rw.printExtended) + } else { + err = PrintViolationsTable(tableContent, rw.scanType, rw.printExtended) + } + if err != nil { + return + } + if rw.includeLicenses { + if err = PrintLicensesTable(tableContent, rw.printExtended, rw.scanType); err != nil { + return + } + } } - if rw.includeLicenses { - if err = PrintLicensesTable(tableContent, rw.printExtended, rw.scanType); err != nil { + if shouldPrintTable(rw.subScansPreformed, utils.SecretsScan, rw.scanType) { + if err = PrintJasTable(tableContent, rw.commandResults.EntitledForJas, jasutils.Secrets); err != nil { return } } - if err = PrintJasTable(tableContent, rw.commandResults.EntitledForJas, jasutils.Secrets); err != nil { - return + if shouldPrintTable(rw.subScansPreformed, utils.IacScan, rw.scanType) { + if err = PrintJasTable(tableContent, rw.commandResults.EntitledForJas, jasutils.IaC); err != nil { + return + } } - if err = PrintJasTable(tableContent, rw.commandResults.EntitledForJas, jasutils.IaC); err != nil { - return + if !shouldPrintTable(rw.subScansPreformed, utils.SastScan, rw.scanType) { + return nil } return PrintJasTable(tableContent, rw.commandResults.EntitledForJas, jasutils.Sast) } diff --git a/utils/results/results.go b/utils/results/results.go index 89945942..f3cfb2e7 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -2,6 +2,7 @@ package results import ( "errors" + "strings" "sync" "github.com/jfrog/gofrog/datastructures" @@ -20,7 +21,7 @@ type SecurityCommandResults struct { MultiScanId string `json:"multi_scan_id,omitempty"` // Results for each target in the command Targets []*TargetResults `json:"targets"` - scansMutex sync.Mutex `json:"-"` + targetsMutex sync.Mutex `json:"-"` // Error that occurred during the command execution Error error `json:"error,omitempty"` } @@ -40,8 +41,7 @@ type TargetResults struct { ScaResults *ScaScanResults `json:"sca_scans,omitempty"` JasResults *JasScansResults `json:"jas_scans,omitempty"` // Errors that occurred during the scans - Errors []error `json:"errors,omitempty"` - // TODO: move to funcs... + Errors []error `json:"errors,omitempty"` errorsMutex sync.Mutex `json:"-"` } @@ -61,7 +61,7 @@ type JasScansResults struct { } func NewCommandResults(xrayVersion string, entitledForJas bool) *SecurityCommandResults { - return &SecurityCommandResults{XrayVersion: xrayVersion, EntitledForJas: entitledForJas, scansMutex: sync.Mutex{}} + return &SecurityCommandResults{XrayVersion: xrayVersion, EntitledForJas: entitledForJas, targetsMutex: sync.Mutex{}} } func (r *SecurityCommandResults) SetMultiScanId(multiScanId string) *SecurityCommandResults { @@ -89,25 +89,25 @@ func (r *SecurityCommandResults) GetJasScansResults(scanType jasutils.JasScanTyp } func (r *SecurityCommandResults) GetErrors() (err error) { - err = r.Errors - for _, scan := range r.Targets { - if scan.Error != nil { - err = errors.Join(err, scan.Error) + err = r.Error + for _, target := range r.Targets { + for _, targetErr := range target.Errors { + err = errors.Join(err, targetErr) } } return } -func (r *SecurityCommandResults) GetTechnologyScaScans(technology techutils.Technology) (scans []*ScaScanResults) { - for _, scan := range r.Targets { - for _, scaResult := range scan.ScaResults { - if scaResult.Technology == technology { - scans = append(scans, scaResult) - } - } - } - return -} +// func (r *SecurityCommandResults) GetTechnologyScaScans(technology techutils.Technology) (scans []*ScaScanResults) { +// for _, scan := range r.Targets { +// for _, scaResult := range scan.ScaResults { +// if scaResult.Technology == technology { +// scans = append(scans, scaResult) +// } +// } +// } +// return +// } func (r *SecurityCommandResults) GetTechnologies() []techutils.Technology { technologies := datastructures.MakeSet[techutils.Technology]() @@ -123,9 +123,9 @@ func (r *SecurityCommandResults) HasMultipleTargets() bool { if len(r.Targets) > 1 { return true } - for _, scan := range r.Targets { + for _, scanTarget := range r.Targets { // If there is more than one SCA scan target (i.e multiple files with dependencies information) - if len(scan.ScaResults) > 1 { + if scanTarget.ScaResults != nil && (len(scanTarget.ScaResults.XrayResults) > 0 || (scanTarget.ScaResults.IsMultipleRootProject != nil && *scanTarget.ScaResults.IsMultipleRootProject)) { return true } } @@ -153,29 +153,40 @@ func (r *SecurityCommandResults) HasFindings() bool { // --- Scan on a target --- func (r *SecurityCommandResults) NewScanResults(target ScanTarget) *TargetResults { - scanResults := &TargetResults{ScanTarget: target, errorsMutex: sync.Mutex{}} + targetResults := &TargetResults{ScanTarget: target, errorsMutex: sync.Mutex{}} if r.EntitledForJas { - scanResults.JasResults = &JasScansResults{} + targetResults.JasResults = &JasScansResults{} } - r.scansMutex.Lock() - r.Targets = append(r.Targets, scanResults) - r.scansMutex.Unlock() - return scanResults + r.targetsMutex.Lock() + r.Targets = append(r.Targets, targetResults) + r.targetsMutex.Unlock() + return targetResults } func (sr *TargetResults) GetScaScansXrayResults() (results []services.ScanResponse) { - for _, scaResult := range sr.ScaResults { - results = append(results, scaResult.XrayResult) + if sr.ScaResults == nil { + return + } + for _, scaResult := range sr.ScaResults.XrayResults { + results = append(results, scaResult) } return } func (sr *TargetResults) GetTechnologies() []techutils.Technology { - technologies := datastructures.MakeSet[techutils.Technology]() - for _, scaResult := range sr.ScaResults { - technologies.Add(scaResult.Technology) + technologiesSet := datastructures.MakeSet[techutils.Technology]() + if sr.Technology != "" { + technologiesSet.Add(sr.Technology) } - return technologies.ToSlice() + if sr.ScaResults == nil { + return technologiesSet.ToSlice() + } + for _, scaResult := range sr.ScaResults.XrayResults { + if scaResult.ScannedPackageType != "" { + technologiesSet.Add(techutils.Technology(strings.ToLower(scaResult.ScannedPackageType))) + } + } + return technologiesSet.ToSlice() } func (sr *TargetResults) GetJasScansResults(scanType jasutils.JasScanType) (results []*sarif.Run) { @@ -186,26 +197,28 @@ func (sr *TargetResults) GetJasScansResults(scanType jasutils.JasScanType) (resu } func (sr *TargetResults) HasInformation() bool { - for _, scaResult := range sr.ScaResults { - if scaResult.HasInformation() { - return true - } + if sr.JasResults != nil && sr.JasResults.HasInformation() { + return true + } + if sr.ScaResults != nil && sr.ScaResults.HasInformation() { + return true } return false } func (sr *TargetResults) HasFindings() bool { - for _, scaResult := range sr.ScaResults { - if scaResult.HasFindings() { - return true - } + if sr.JasResults != nil && sr.JasResults.HasFindings() { + return true + } + if sr.ScaResults != nil && sr.ScaResults.HasFindings() { + return true } return false } func (sr *TargetResults) AddError(err error) { sr.errorsMutex.Lock() - sr.Error = errors.Join(sr.Error, err) + sr.Errors = append(sr.Errors, err) sr.errorsMutex.Unlock() } @@ -218,42 +231,35 @@ func (sr *TargetResults) SetDescriptors(descriptors ...string) *TargetResults { } func (sr *TargetResults) NewScaScanResults(responses ...*services.ScanResponse) *ScaScanResults { - scaScanResults := NewScaScanResults(response) - sr.ScaResults = append(sr.ScaResults, scaScanResults) - return scaScanResults -} - -func (sr *TargetResults) NewScaScan(descriptors ...string) *ScaScanResults { - scaScanResults := &ScaScanResults{Descriptors: descriptors} - sr.ScaResults = append(sr.ScaResults, scaScanResults) - return scaScanResults -} - -func NewScaScanResults(response *services.ScanResponse) *ScaScanResults { - return &ScaScanResults{XrayResult: *response} -} - -func (ssr *ScaScanResults) SetDescriptor(descriptor string) *ScaScanResults { - ssr.Target = descriptor - return ssr -} - -func (ssr *ScaScanResults) SetTechnology(technology techutils.Technology) *ScaScanResults { - ssr.Technology = technology - return ssr -} - -func (ssr *ScaScanResults) SetXrayScanResults(response *services.ScanResponse) *ScaScanResults { - ssr.XrayResult = *response - return ssr + results := sr.ScaResults + if results == nil { + results = &ScaScanResults{} + } + for _, response := range responses { + results.XrayResults = append(results.XrayResults, *response) + } + return results } func (ssr *ScaScanResults) HasInformation() bool { - return ssr.HasFindings() || len(ssr.XrayResult.Licenses) > 0 + if ssr.HasFindings() { + return true + } + for _, scanResults := range ssr.XrayResults { + if len(scanResults.Licenses) > 0 { + return true + } + } + return false } func (ssr *ScaScanResults) HasFindings() bool { - return len(ssr.XrayResult.Vulnerabilities) > 0 || len(ssr.XrayResult.Violations) > 0 + for _, scanResults := range ssr.XrayResults { + if len(scanResults.Vulnerabilities) > 0 || len(scanResults.Violations) > 0 { + return true + } + } + return false } func (jsr *JasScansResults) GetResults(scanType jasutils.JasScanType) (results []*sarif.Run) { @@ -270,143 +276,40 @@ func (jsr *JasScansResults) GetResults(scanType jasutils.JasScanType) (results [ return } -// func NewAuditResults() *ScanCommandResults { -// return &ScanCommandResults{ExtendedScanResults: &ExtendedScanResults{}} -// } - -// func (r *ScanCommandResults) GetScaScansXrayResults() (results []services.ScanResponse) { -// for _, scaResult := range r.ScaResults { -// results = append(results, scaResult.XrayResults...) -// } -// return -// } - -// func (r *ScanCommandResults) GetScaScannedTechnologies() []techutils.Technology { -// technologies := datastructures.MakeSet[techutils.Technology]() -// for _, scaResult := range r.ScaResults { -// technologies.Add(scaResult.Technology) -// } -// return technologies.ToSlice() -// } - -// func (r *ScanCommandResults) IsMultipleProject() bool { -// if len(r.ScaResults) == 0 { -// return false -// } -// if len(r.ScaResults) == 1 { -// if r.ScaResults[0].IsMultipleRootProject == nil { -// return false -// } -// return *r.ScaResults[0].IsMultipleRootProject -// } -// return true -// } - -// func (r *ScanCommandResults) IsScaIssuesFound() bool { -// for _, scan := range r.ScaResults { -// if scan.HasInformation() { -// return true -// } -// } -// return false -// } - -// func (r *ScanCommandResults) getScaScanResultByTarget(target string) *ScaScanResult { -// for _, scan := range r.ScaResults { -// if scan.Target == target { -// return scan -// } -// } -// return nil -// } - -// func (r *ScanCommandResults) IsIssuesFound() bool { -// if r.IsScaIssuesFound() { -// return true -// } -// if r.ExtendedScanResults.IsIssuesFound() { -// return true -// } -// return false -// } - -// // Counts the total number of unique findings in the provided results. -// // A unique SCA finding is identified by a unique pair of vulnerability's/violation's issueId and component id or by a result returned from one of JAS scans. -// func (r *ScanCommandResults) CountScanResultsFindings() (total int) { -// return formats.SummaryResults{Scans: r.getScanSummaryByTargets()}.GetTotalIssueCount() -// } -// func (r *ScanCommandResults) GetSummary() (summary formats.SummaryResults) { -// if len(r.ScaResults) <= 1 { -// summary.Scans = r.getScanSummaryByTargets() -// return -// } -// for _, scaScan := range r.ScaResults { -// summary.Scans = append(summary.Scans, r.getScanSummaryByTargets(scaScan.Target)...) -// } -// return -// } - -// // Returns a summary for the provided targets. If no targets are provided, a summary for all targets is returned. -// func (r *ScanCommandResults) getScanSummaryByTargets(targets ...string) (summaries []formats.ScanSummaryResult) { -// if len(targets) == 0 { -// // No filter, one scan summary for all targets -// summaries = append(summaries, getScanSummary(r.ExtendedScanResults, r.ScaResults...)) -// return -// } -// for _, target := range targets { -// // Get target sca results -// targetScaResults := []*ScaScanResult{} -// if targetScaResult := r.getScaScanResultByTarget(target); targetScaResult != nil { -// targetScaResults = append(targetScaResults, targetScaResult) -// } -// // Get target extended results -// targetExtendedResults := r.ExtendedScanResults -// if targetExtendedResults != nil { -// targetExtendedResults = targetExtendedResults.GetResultsForTarget(target) -// } -// summaries = append(summaries, getScanSummary(targetExtendedResults, targetScaResults...)) -// } -// return -// } - -// type ScaScanResult struct { -// // Could be working directory (audit), file path (binary scan) or build name+number (build scan) -// Target string `json:"Target"` -// Technology techutils.Technology `json:"Technology,omitempty"` -// XrayResults []services.ScanResponse `json:"XrayResults,omitempty"` -// Descriptors []string `json:"Descriptors,omitempty"` -// IsMultipleRootProject *bool `json:"IsMultipleRootProject,omitempty"` -// } - -// func (s ScaScanResult) HasInformation() bool { -// for _, scan := range s.XrayResults { -// if len(scan.Vulnerabilities) > 0 || len(scan.Violations) > 0 || len(scan.Licenses) > 0 { -// return true -// } -// } -// return false -// } +func (jsr *JasScansResults) HasFindings() bool { + for _, scanType := range jasutils.GetJasScanTypes() { + if jsr.HasFindingsByType(scanType) { + return true + } + } + return false +} -// type ExtendedScanResults struct { -// ApplicabilityScanResults []*sarif.Run -// SecretsScanResults []*sarif.Run -// IacScanResults []*sarif.Run -// SastScanResults []*sarif.Run -// EntitledForJas bool -// } +func (jsr *JasScansResults) HasFindingsByType(scanType jasutils.JasScanType) bool { + for _, run := range jsr.GetResults(scanType) { + for _, result := range run.Results { + if len(result.Locations) > 0 { + return true + } + } + } + return false +} -// func (e *ExtendedScanResults) IsIssuesFound() bool { -// return sarifutils.GetResultsLocationCount(e.ApplicabilityScanResults...) > 0 || -// sarifutils.GetResultsLocationCount(e.SecretsScanResults...) > 0 || -// sarifutils.GetResultsLocationCount(e.IacScanResults...) > 0 || -// sarifutils.GetResultsLocationCount(e.SastScanResults...) > 0 -// } +func (jsr *JasScansResults) HasInformation() bool { + for _, scanType := range jasutils.GetJasScanTypes() { + if jsr.HasInformationByType(scanType) { + return true + } + } + return false +} -// func (e *ExtendedScanResults) GetResultsForTarget(target string) (result *ExtendedScanResults) { -// return &ExtendedScanResults{ -// ApplicabilityScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.ApplicabilityScanResults...), -// SecretsScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.SecretsScanResults...), -// IacScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.IacScanResults...), -// SastScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.SastScanResults...), -// } -// } +func (jsr *JasScansResults) HasInformationByType(scanType jasutils.JasScanType) bool { + for _, run := range jsr.GetResults(scanType) { + if len(run.Results) > 0 { + return true + } + } + return false +} \ No newline at end of file diff --git a/utils/results/results_test.go b/utils/results/results_test.go index cc5bc803..1e55d391 100644 --- a/utils/results/results_test.go +++ b/utils/results/results_test.go @@ -1,203 +1,203 @@ package results import ( - "testing" + // "testing" - "github.com/jfrog/jfrog-cli-security/utils/formats" - "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" - "github.com/jfrog/jfrog-client-go/xray/services" - "github.com/owenrumney/go-sarif/v2/sarif" - "github.com/stretchr/testify/assert" + // "github.com/jfrog/jfrog-cli-security/utils/formats" + // "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" + // "github.com/jfrog/jfrog-client-go/xray/services" + // "github.com/owenrumney/go-sarif/v2/sarif" + // "github.com/stretchr/testify/assert" ) -func TestGetScaScanResultByTarget(t *testing.T) { - target1 := &ScaScanResult{Target: "target1"} - target2 := &ScaScanResult{Target: "target2"} - testCases := []struct { - name string - cmdResults SecurityCommandResults - target string - expected *ScaScanResult - }{ - { - name: "Sca scan result by target", - cmdResults: SecurityCommandResults{ - ScaResults: []*ScaScanResult{ - target1, - target2, - }, - }, - target: "target1", - expected: target1, - }, - { - name: "Sca scan result by target not found", - cmdResults: SecurityCommandResults{ - ScaResults: []*ScaScanResult{ - target1, - target2, - }, - }, - target: "target3", - expected: nil, - }, - } - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - result := testCase.cmdResults.getScaScanResultByTarget(testCase.target) - assert.Equal(t, testCase.expected, result) - }) - } -} +// func TestGetScaScanResultByTarget(t *testing.T) { +// target1 := &ScaScanResult{Target: "target1"} +// target2 := &ScaScanResult{Target: "target2"} +// testCases := []struct { +// name string +// cmdResults SecurityCommandResults +// target string +// expected *ScaScanResult +// }{ +// { +// name: "Sca scan result by target", +// cmdResults: SecurityCommandResults{ +// ScaResults: []*ScaScanResult{ +// target1, +// target2, +// }, +// }, +// target: "target1", +// expected: target1, +// }, +// { +// name: "Sca scan result by target not found", +// cmdResults: SecurityCommandResults{ +// ScaResults: []*ScaScanResult{ +// target1, +// target2, +// }, +// }, +// target: "target3", +// expected: nil, +// }, +// } +// for _, testCase := range testCases { +// t.Run(testCase.name, func(t *testing.T) { +// result := testCase.cmdResults.getScaScanResultByTarget(testCase.target) +// assert.Equal(t, testCase.expected, result) +// }) +// } +// } -func TestGetSummary(t *testing.T) { - dummyExtendedScanResults := &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyPassingResult("applic_CVE-2")).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target1")), - }), - }, - SecretsScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("target1/file", 0, 0, 0, 0, "snippet"))).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target1")), - }), - sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("target2/file", 0, 0, 0, 0, "snippet"))).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target2")), - }), - }, - SastScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("target1/file2", 0, 0, 0, 0, "snippet"))).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target1")), - }), - }, - } +// func TestGetSummary(t *testing.T) { +// dummyExtendedScanResults := &ExtendedScanResults{ +// ApplicabilityScanResults: []*sarif.Run{ +// sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyPassingResult("applic_CVE-2")).WithInvocations([]*sarif.Invocation{ +// sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target1")), +// }), +// }, +// SecretsScanResults: []*sarif.Run{ +// sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("target1/file", 0, 0, 0, 0, "snippet"))).WithInvocations([]*sarif.Invocation{ +// sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target1")), +// }), +// sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("target2/file", 0, 0, 0, 0, "snippet"))).WithInvocations([]*sarif.Invocation{ +// sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target2")), +// }), +// }, +// SastScanResults: []*sarif.Run{ +// sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("target1/file2", 0, 0, 0, 0, "snippet"))).WithInvocations([]*sarif.Invocation{ +// sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target1")), +// }), +// }, +// } - testCases := []struct { - name string - cmdResults SecurityCommandResults - expected formats.SummaryResults - findingCount int - issueCount int - }{ - { - name: "Empty results", - cmdResults: SecurityCommandResults{ScaResults: []*ScaScanResult{}}, - expected: formats.SummaryResults{Scans: []formats.ScanSummaryResult{{}}}, - findingCount: 0, - issueCount: 0, - }, - { - name: "One module result", - cmdResults: SecurityCommandResults{ - ScaResults: []*ScaScanResult{{ - Target: "target1", - XrayResults: getDummyScaTestResults(true, false), - }}, - ExtendedScanResults: dummyExtendedScanResults, - }, - expected: formats.SummaryResults{ - Scans: []formats.ScanSummaryResult{ - { - Target: "target1", - Vulnerabilities: &formats.ScanVulnerabilitiesSummary{ - ScaScanResults: &formats.ScanScaResult{ - SummaryCount: formats.TwoLevelSummaryCount{ - "Critical": formats.SummaryCount{"Undetermined": 1}, - "High": formats.SummaryCount{"Not Applicable": 1}, - }, - UniqueFindings: 2, - }, - SecretsScanResults: &formats.SummaryCount{"Low": 2}, - SastScanResults: &formats.SummaryCount{"Low": 1}, - }, - Violations: formats.TwoLevelSummaryCount{}, - }, - }, - }, - findingCount: 5, - issueCount: 5, - }, - { - name: "Multiple module results", - cmdResults: SecurityCommandResults{ - ScaResults: []*ScaScanResult{ - { - Target: "target1", - XrayResults: getDummyScaTestResults(false, true), - }, - { - Target: "target2", - XrayResults: getDummyScaTestResults(true, true), - }, - }, - ExtendedScanResults: dummyExtendedScanResults, - }, - expected: formats.SummaryResults{ - Scans: []formats.ScanSummaryResult{ - { - Target: "target1", - Vulnerabilities: &formats.ScanVulnerabilitiesSummary{ - ScaScanResults: &formats.ScanScaResult{SummaryCount: formats.TwoLevelSummaryCount{}}, - SecretsScanResults: &formats.SummaryCount{"Low": 1}, - SastScanResults: &formats.SummaryCount{"Low": 1}, - }, - Violations: formats.TwoLevelSummaryCount{ - formats.ViolationTypeSecurity.String(): formats.SummaryCount{"Critical": 1, "High": 1}, - formats.ViolationTypeLicense.String(): formats.SummaryCount{"High": 1}, - }, - }, - { - Target: "target2", - Vulnerabilities: &formats.ScanVulnerabilitiesSummary{ - ScaScanResults: &formats.ScanScaResult{ - SummaryCount: formats.TwoLevelSummaryCount{"Critical": formats.SummaryCount{"": 1}}, - UniqueFindings: 1, - }, - SecretsScanResults: &formats.SummaryCount{"Low": 1}, - }, - Violations: formats.TwoLevelSummaryCount{formats.ViolationTypeSecurity.String(): formats.SummaryCount{"High": 1}}, - }, - }, - }, - findingCount: 7, - issueCount: 8, - }, - } - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - result := testCase.cmdResults.GetSummary() - assert.Equal(t, testCase.expected, result) - assert.Equal(t, testCase.findingCount, testCase.cmdResults.CountScanResultsFindings()) - assert.Equal(t, testCase.issueCount, testCase.cmdResults.GetSummary().GetTotalIssueCount()) - }) - } -} +// testCases := []struct { +// name string +// cmdResults SecurityCommandResults +// expected formats.SummaryResults +// findingCount int +// issueCount int +// }{ +// { +// name: "Empty results", +// cmdResults: SecurityCommandResults{ScaResults: []*ScaScanResult{}}, +// expected: formats.SummaryResults{Scans: []formats.ScanSummaryResult{{}}}, +// findingCount: 0, +// issueCount: 0, +// }, +// { +// name: "One module result", +// cmdResults: SecurityCommandResults{ +// ScaResults: []*ScaScanResult{{ +// Target: "target1", +// XrayResults: getDummyScaTestResults(true, false), +// }}, +// ExtendedScanResults: dummyExtendedScanResults, +// }, +// expected: formats.SummaryResults{ +// Scans: []formats.ScanSummaryResult{ +// { +// Target: "target1", +// Vulnerabilities: &formats.ScanVulnerabilitiesSummary{ +// ScaScanResults: &formats.ScanScaResult{ +// SummaryCount: formats.TwoLevelSummaryCount{ +// "Critical": formats.SummaryCount{"Undetermined": 1}, +// "High": formats.SummaryCount{"Not Applicable": 1}, +// }, +// UniqueFindings: 2, +// }, +// SecretsScanResults: &formats.SummaryCount{"Low": 2}, +// SastScanResults: &formats.SummaryCount{"Low": 1}, +// }, +// Violations: formats.TwoLevelSummaryCount{}, +// }, +// }, +// }, +// findingCount: 5, +// issueCount: 5, +// }, +// { +// name: "Multiple module results", +// cmdResults: SecurityCommandResults{ +// ScaResults: []*ScaScanResult{ +// { +// Target: "target1", +// XrayResults: getDummyScaTestResults(false, true), +// }, +// { +// Target: "target2", +// XrayResults: getDummyScaTestResults(true, true), +// }, +// }, +// ExtendedScanResults: dummyExtendedScanResults, +// }, +// expected: formats.SummaryResults{ +// Scans: []formats.ScanSummaryResult{ +// { +// Target: "target1", +// Vulnerabilities: &formats.ScanVulnerabilitiesSummary{ +// ScaScanResults: &formats.ScanScaResult{SummaryCount: formats.TwoLevelSummaryCount{}}, +// SecretsScanResults: &formats.SummaryCount{"Low": 1}, +// SastScanResults: &formats.SummaryCount{"Low": 1}, +// }, +// Violations: formats.TwoLevelSummaryCount{ +// formats.ViolationTypeSecurity.String(): formats.SummaryCount{"Critical": 1, "High": 1}, +// formats.ViolationTypeLicense.String(): formats.SummaryCount{"High": 1}, +// }, +// }, +// { +// Target: "target2", +// Vulnerabilities: &formats.ScanVulnerabilitiesSummary{ +// ScaScanResults: &formats.ScanScaResult{ +// SummaryCount: formats.TwoLevelSummaryCount{"Critical": formats.SummaryCount{"": 1}}, +// UniqueFindings: 1, +// }, +// SecretsScanResults: &formats.SummaryCount{"Low": 1}, +// }, +// Violations: formats.TwoLevelSummaryCount{formats.ViolationTypeSecurity.String(): formats.SummaryCount{"High": 1}}, +// }, +// }, +// }, +// findingCount: 7, +// issueCount: 8, +// }, +// } +// for _, testCase := range testCases { +// t.Run(testCase.name, func(t *testing.T) { +// result := testCase.cmdResults.GetSummary() +// assert.Equal(t, testCase.expected, result) +// assert.Equal(t, testCase.findingCount, testCase.cmdResults.CountScanResultsFindings()) +// assert.Equal(t, testCase.issueCount, testCase.cmdResults.GetSummary().GetTotalIssueCount()) +// }) +// } +// } -func getDummyScaTestResults(vulnerability, violation bool) (responses []services.ScanResponse) { - response := services.ScanResponse{} - switch { - case vulnerability && violation: - // Mix - response.Vulnerabilities = []services.Vulnerability{ - {IssueId: "XRAY-1", Severity: "Critical", Cves: []services.Cve{{Id: "CVE-1"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, - } - response.Violations = []services.Violation{ - {ViolationType: formats.ViolationTypeSecurity.String(), WatchName: "test-watch-name", IssueId: "XRAY-2", Severity: "High", Cves: []services.Cve{{Id: "CVE-2"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, - } - case vulnerability: - // only vulnerability - response.Vulnerabilities = []services.Vulnerability{ - {IssueId: "XRAY-1", Severity: "Critical", Cves: []services.Cve{{Id: "CVE-1"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, - {IssueId: "XRAY-2", Severity: "High", Cves: []services.Cve{{Id: "CVE-2"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, - } - case violation: - // only violation - response.Violations = []services.Violation{ - {ViolationType: formats.ViolationTypeSecurity.String(), WatchName: "test-watch-name", IssueId: "XRAY-1", Severity: "Critical", Cves: []services.Cve{{Id: "CVE-1"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, - {ViolationType: formats.ViolationTypeSecurity.String(), WatchName: "test-watch-name", IssueId: "XRAY-2", Severity: "High", Cves: []services.Cve{{Id: "CVE-2"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, - {ViolationType: formats.ViolationTypeLicense.String(), WatchName: "test-watch-name", IssueId: "MIT", Severity: "High", LicenseKey: "MIT", Components: map[string]services.Component{"issueId_direct_dependency": {}}}, - } - } - responses = append(responses, response) - return -} +// func getDummyScaTestResults(vulnerability, violation bool) (responses []services.ScanResponse) { +// response := services.ScanResponse{} +// switch { +// case vulnerability && violation: +// // Mix +// response.Vulnerabilities = []services.Vulnerability{ +// {IssueId: "XRAY-1", Severity: "Critical", Cves: []services.Cve{{Id: "CVE-1"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, +// } +// response.Violations = []services.Violation{ +// {ViolationType: formats.ViolationTypeSecurity.String(), WatchName: "test-watch-name", IssueId: "XRAY-2", Severity: "High", Cves: []services.Cve{{Id: "CVE-2"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, +// } +// case vulnerability: +// // only vulnerability +// response.Vulnerabilities = []services.Vulnerability{ +// {IssueId: "XRAY-1", Severity: "Critical", Cves: []services.Cve{{Id: "CVE-1"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, +// {IssueId: "XRAY-2", Severity: "High", Cves: []services.Cve{{Id: "CVE-2"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, +// } +// case violation: +// // only violation +// response.Violations = []services.Violation{ +// {ViolationType: formats.ViolationTypeSecurity.String(), WatchName: "test-watch-name", IssueId: "XRAY-1", Severity: "Critical", Cves: []services.Cve{{Id: "CVE-1"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, +// {ViolationType: formats.ViolationTypeSecurity.String(), WatchName: "test-watch-name", IssueId: "XRAY-2", Severity: "High", Cves: []services.Cve{{Id: "CVE-2"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, +// {ViolationType: formats.ViolationTypeLicense.String(), WatchName: "test-watch-name", IssueId: "MIT", Severity: "High", LicenseKey: "MIT", Components: map[string]services.Component{"issueId_direct_dependency": {}}}, +// } +// } +// responses = append(responses, response) +// return +// } diff --git a/utils/resultstable.go b/utils/resultstable.go deleted file mode 100644 index 26a2791a..00000000 --- a/utils/resultstable.go +++ /dev/null @@ -1,967 +0,0 @@ -package utils - -import ( - "fmt" - "os" - "path/filepath" - "sort" - "strconv" - "strings" - - "github.com/jfrog/gofrog/datastructures" - "github.com/owenrumney/go-sarif/v2/sarif" - - "github.com/jfrog/jfrog-cli-security/utils/formats" - "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" - "github.com/jfrog/jfrog-cli-security/utils/jasutils" - "github.com/jfrog/jfrog-cli-security/utils/severityutils" - "github.com/jfrog/jfrog-cli-security/utils/techutils" - - "github.com/gookit/color" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-client-go/utils/errorutils" - "github.com/jfrog/jfrog-client-go/utils/log" - "github.com/jfrog/jfrog-client-go/xray/services" -) - -const ( - rootIndex = 0 - directDependencyIndex = 1 - directDependencyPathLength = 2 - nodeModules = "node_modules" - NpmPackageTypeIdentifier = "npm://" -) - -// PrintViolationsTable prints the violations in 4 tables: security violations, license compliance violations, operational risk violations and ignore rule URLs. -// Set multipleRoots to true in case the given violations array contains (or may contain) results of several projects or files (like in binary scan). -// In case multipleRoots is true, the field Component will show the root of each impact path, otherwise it will show the root's child. -// In case one (or more) of the violations contains the field FailBuild set to true, CliError with exit code 3 will be returned. -// Set printExtended to true to print fields with 'extended' tag. -// If the scan argument is set to true, print the scan tables. -func PrintViolationsTable(violations []services.Violation, cmdResults *ScanCommandResults, multipleRoots, printExtended bool, scanType services.ScanType) error { - securityViolationsRows, licenseViolationsRows, operationalRiskViolationsRows, err := prepareViolations(violations, cmdResults, multipleRoots, true, true) - if err != nil { - return err - } - // Print tables, if scan is true; print the scan tables. - if scanType == services.Binary { - err = coreutils.PrintTable(formats.ConvertToVulnerabilityScanTableRow(securityViolationsRows), "Security Violations", "No security violations were found", printExtended) - if err != nil { - return err - } - err = coreutils.PrintTable(formats.ConvertToLicenseViolationScanTableRow(licenseViolationsRows), "License Compliance Violations", "No license compliance violations were found", printExtended) - if err != nil { - return err - } - if len(operationalRiskViolationsRows) > 0 { - return coreutils.PrintTable(formats.ConvertToOperationalRiskViolationScanTableRow(operationalRiskViolationsRows), "Operational Risk Violations", "No operational risk violations were found", printExtended) - } - } else { - err = coreutils.PrintTable(formats.ConvertToVulnerabilityTableRow(securityViolationsRows), "Security Violations", "No security violations were found", printExtended) - if err != nil { - return err - } - err = coreutils.PrintTable(formats.ConvertToLicenseViolationTableRow(licenseViolationsRows), "License Compliance Violations", "No license compliance violations were found", printExtended) - if err != nil { - return err - } - if len(operationalRiskViolationsRows) > 0 { - return coreutils.PrintTable(formats.ConvertToOperationalRiskViolationTableRow(operationalRiskViolationsRows), "Operational Risk Violations", "No operational risk violations were found", printExtended) - } - } - return nil -} - -// Prepare violations for all non-table formats (without style or emoji) -func PrepareViolations(violations []services.Violation, cmdResults *ScanCommandResults, multipleRoots, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, []formats.LicenseRow, []formats.OperationalRiskViolationRow, error) { - return prepareViolations(violations, cmdResults, multipleRoots, false, simplifiedOutput) -} - -func prepareViolations(violations []services.Violation, cmdResults *ScanCommandResults, multipleRoots, isTable, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, []formats.LicenseRow, []formats.OperationalRiskViolationRow, error) { - if simplifiedOutput { - violations = simplifyViolations(violations, multipleRoots) - } - var securityViolationsRows []formats.VulnerabilityOrViolationRow - var licenseViolationsRows []formats.LicenseRow - var operationalRiskViolationsRows []formats.OperationalRiskViolationRow - for _, violation := range violations { - impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, fixedVersions, components, impactPaths, err := splitComponents(violation.Components) - if err != nil { - return nil, nil, nil, err - } - switch violation.ViolationType { - case formats.ViolationTypeSecurity.String(): - cves := convertCves(violation.Cves) - if cmdResults.ExtendedScanResults.EntitledForJas { - for i := range cves { - cves[i].Applicability = getCveApplicabilityField(cves[i].Id, cmdResults.ExtendedScanResults.ApplicabilityScanResults, violation.Components) - } - } - applicabilityStatus := getApplicableCveStatus(cmdResults.ExtendedScanResults.EntitledForJas, cmdResults.ExtendedScanResults.ApplicabilityScanResults, cves) - currSeverity, err := severityutils.ParseSeverity(violation.Severity, false) - if err != nil { - return nil, nil, nil, err - } - jfrogResearchInfo := convertJfrogResearchInformation(violation.ExtendedInformation) - for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { - securityViolationsRows = append(securityViolationsRows, - formats.VulnerabilityOrViolationRow{ - Summary: violation.Summary, - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: severityutils.GetAsDetails(currSeverity, applicabilityStatus, isTable), - ImpactedDependencyName: impactedPackagesNames[compIndex], - ImpactedDependencyVersion: impactedPackagesVersions[compIndex], - ImpactedDependencyType: impactedPackagesTypes[compIndex], - Components: components[compIndex], - }, - FixedVersions: fixedVersions[compIndex], - Cves: cves, - IssueId: violation.IssueId, - References: violation.References, - JfrogResearchInformation: jfrogResearchInfo, - ImpactPaths: impactPaths[compIndex], - Technology: techutils.Technology(violation.Technology), - Applicable: printApplicabilityCveValue(applicabilityStatus, isTable), - }, - ) - } - case formats.ViolationTypeLicense.String(): - currSeverity, err := severityutils.ParseSeverity(violation.Severity, false) - if err != nil { - return nil, nil, nil, err - } - for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { - licenseViolationsRows = append(licenseViolationsRows, - formats.LicenseRow{ - LicenseKey: violation.LicenseKey, - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: severityutils.GetAsDetails(currSeverity, jasutils.NotScanned, isTable), - ImpactedDependencyName: impactedPackagesNames[compIndex], - ImpactedDependencyVersion: impactedPackagesVersions[compIndex], - ImpactedDependencyType: impactedPackagesTypes[compIndex], - Components: components[compIndex], - }, - }, - ) - } - case formats.ViolationTypeOperationalRisk.String(): - currSeverity, err := severityutils.ParseSeverity(violation.Severity, false) - if err != nil { - return nil, nil, nil, err - } - violationOpRiskData := getOperationalRiskViolationReadableData(violation) - for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { - operationalRiskViolationsRow := &formats.OperationalRiskViolationRow{ - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: severityutils.GetAsDetails(currSeverity, jasutils.NotScanned, isTable), - ImpactedDependencyName: impactedPackagesNames[compIndex], - ImpactedDependencyVersion: impactedPackagesVersions[compIndex], - ImpactedDependencyType: impactedPackagesTypes[compIndex], - Components: components[compIndex], - }, - IsEol: violationOpRiskData.isEol, - Cadence: violationOpRiskData.cadence, - Commits: violationOpRiskData.commits, - Committers: violationOpRiskData.committers, - NewerVersions: violationOpRiskData.newerVersions, - LatestVersion: violationOpRiskData.latestVersion, - RiskReason: violationOpRiskData.riskReason, - EolMessage: violationOpRiskData.eolMessage, - } - operationalRiskViolationsRows = append(operationalRiskViolationsRows, *operationalRiskViolationsRow) - } - default: - // Unsupported type, ignore - } - } - - // Sort the rows by severity and whether the row contains fixed versions - sortVulnerabilityOrViolationRows(securityViolationsRows) - sort.Slice(licenseViolationsRows, func(i, j int) bool { - return licenseViolationsRows[i].SeverityNumValue > licenseViolationsRows[j].SeverityNumValue - }) - sort.Slice(operationalRiskViolationsRows, func(i, j int) bool { - return operationalRiskViolationsRows[i].SeverityNumValue > operationalRiskViolationsRows[j].SeverityNumValue - }) - - return securityViolationsRows, licenseViolationsRows, operationalRiskViolationsRows, nil -} - -// PrintVulnerabilitiesTable prints the vulnerabilities in a table. -// Set multipleRoots to true in case the given vulnerabilities array contains (or may contain) results of several projects or files (like in binary scan). -// In case multipleRoots is true, the field Component will show the root of each impact path, otherwise it will show the root's child. -// Set printExtended to true to print fields with 'extended' tag. -// If the scan argument is set to true, print the scan tables. -func PrintVulnerabilitiesTable(vulnerabilities []services.Vulnerability, cmdResults *ScanCommandResults, multipleRoots, printExtended bool, scanType services.ScanType) error { - vulnerabilitiesRows, err := prepareVulnerabilities(vulnerabilities, cmdResults, multipleRoots, true, true) - if err != nil { - return err - } - - if scanType == services.Binary { - return coreutils.PrintTable(formats.ConvertToVulnerabilityScanTableRow(vulnerabilitiesRows), "Vulnerable Components", "✨ No vulnerable components were found ✨", printExtended) - } - var emptyTableMessage string - if len(cmdResults.ScaResults) > 0 { - emptyTableMessage = "✨ No vulnerable dependencies were found ✨" - } else { - emptyTableMessage = coreutils.PrintYellow("🔧 Couldn't determine a package manager or build tool used by this project 🔧") - } - return coreutils.PrintTable(formats.ConvertToVulnerabilityTableRow(vulnerabilitiesRows), "Vulnerable Dependencies", emptyTableMessage, printExtended) -} - -// Prepare vulnerabilities for all non-table formats (without style or emoji) -func PrepareVulnerabilities(vulnerabilities []services.Vulnerability, cmdResults *ScanCommandResults, multipleRoots, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, error) { - return prepareVulnerabilities(vulnerabilities, cmdResults, multipleRoots, false, simplifiedOutput) -} - -func prepareVulnerabilities(vulnerabilities []services.Vulnerability, cmdResults *ScanCommandResults, multipleRoots, isTable, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, error) { - if simplifiedOutput { - vulnerabilities = simplifyVulnerabilities(vulnerabilities, multipleRoots) - } - var vulnerabilitiesRows []formats.VulnerabilityOrViolationRow - for _, vulnerability := range vulnerabilities { - impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, fixedVersions, components, impactPaths, err := splitComponents(vulnerability.Components) - if err != nil { - return nil, err - } - cves := convertCves(vulnerability.Cves) - if cmdResults.ExtendedScanResults.EntitledForJas { - for i := range cves { - cves[i].Applicability = getCveApplicabilityField(cves[i].Id, cmdResults.ExtendedScanResults.ApplicabilityScanResults, vulnerability.Components) - } - } - applicabilityStatus := getApplicableCveStatus(cmdResults.ExtendedScanResults.EntitledForJas, cmdResults.ExtendedScanResults.ApplicabilityScanResults, cves) - currSeverity, err := severityutils.ParseSeverity(vulnerability.Severity, false) - if err != nil { - return nil, err - } - jfrogResearchInfo := convertJfrogResearchInformation(vulnerability.ExtendedInformation) - for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { - vulnerabilitiesRows = append(vulnerabilitiesRows, - formats.VulnerabilityOrViolationRow{ - Summary: vulnerability.Summary, - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: severityutils.GetAsDetails(currSeverity, applicabilityStatus, isTable), - ImpactedDependencyName: impactedPackagesNames[compIndex], - ImpactedDependencyVersion: impactedPackagesVersions[compIndex], - ImpactedDependencyType: impactedPackagesTypes[compIndex], - Components: components[compIndex], - }, - FixedVersions: fixedVersions[compIndex], - Cves: cves, - IssueId: vulnerability.IssueId, - References: vulnerability.References, - JfrogResearchInformation: jfrogResearchInfo, - ImpactPaths: impactPaths[compIndex], - Technology: techutils.Technology(vulnerability.Technology), - Applicable: printApplicabilityCveValue(applicabilityStatus, isTable), - }, - ) - } - } - - sortVulnerabilityOrViolationRows(vulnerabilitiesRows) - return vulnerabilitiesRows, nil -} - -func sortVulnerabilityOrViolationRows(rows []formats.VulnerabilityOrViolationRow) { - sort.Slice(rows, func(i, j int) bool { - if rows[i].SeverityNumValue != rows[j].SeverityNumValue { - return rows[i].SeverityNumValue > rows[j].SeverityNumValue - } - return len(rows[i].FixedVersions) > 0 && len(rows[j].FixedVersions) > 0 - }) -} - -// PrintLicensesTable prints the licenses in a table. -// Set multipleRoots to true in case the given licenses array contains (or may contain) results of several projects or files (like in binary scan). -// In case multipleRoots is true, the field Component will show the root of each impact path, otherwise it will show the root's child. -// Set printExtended to true to print fields with 'extended' tag. -// If the scan argument is set to true, print the scan tables. -func PrintLicensesTable(licenses []services.License, printExtended bool, scanType services.ScanType) error { - licensesRows, err := PrepareLicenses(licenses) - if err != nil { - return err - } - if scanType == services.Binary { - return coreutils.PrintTable(formats.ConvertToLicenseScanTableRow(licensesRows), "Licenses", "No licenses were found", printExtended) - } - return coreutils.PrintTable(formats.ConvertToLicenseTableRow(licensesRows), "Licenses", "No licenses were found", printExtended) -} - -func PrepareLicenses(licenses []services.License) ([]formats.LicenseRow, error) { - var licensesRows []formats.LicenseRow - for _, license := range licenses { - impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, _, components, impactPaths, err := splitComponents(license.Components) - if err != nil { - return nil, err - } - for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { - licensesRows = append(licensesRows, - formats.LicenseRow{ - LicenseKey: license.Key, - ImpactPaths: impactPaths[compIndex], - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - ImpactedDependencyName: impactedPackagesNames[compIndex], - ImpactedDependencyVersion: impactedPackagesVersions[compIndex], - ImpactedDependencyType: impactedPackagesTypes[compIndex], - Components: components[compIndex], - }, - }, - ) - } - } - - return licensesRows, nil -} - -// Prepare secrets for all non-table formats (without style or emoji) -func PrepareSecrets(secrets []*sarif.Run) []formats.SourceCodeRow { - return prepareSecrets(secrets, false) -} - -func prepareSecrets(secrets []*sarif.Run, isTable bool) []formats.SourceCodeRow { - var secretsRows []formats.SourceCodeRow - for _, secretRun := range secrets { - for _, secretResult := range secretRun.Results { - currSeverity, err := severityutils.ParseSeverity(sarifutils.GetResultLevel(secretResult), true) - if err != nil { - log.Warn(fmt.Sprintf("Failed to parse severity `%s` for secret result: %s", sarifutils.GetResultLevel(secretResult), *secretResult.RuleID)) - currSeverity = severityutils.Unknown - } - for _, location := range secretResult.Locations { - secretsRows = append(secretsRows, - formats.SourceCodeRow{ - SeverityDetails: severityutils.GetAsDetails(currSeverity, jasutils.Applicable, isTable), - Finding: sarifutils.GetResultMsgText(secretResult), - Location: formats.Location{ - File: sarifutils.GetRelativeLocationFileName(location, secretRun.Invocations), - StartLine: sarifutils.GetLocationStartLine(location), - StartColumn: sarifutils.GetLocationStartColumn(location), - EndLine: sarifutils.GetLocationEndLine(location), - EndColumn: sarifutils.GetLocationEndColumn(location), - Snippet: sarifutils.GetLocationSnippet(location), - }, - }, - ) - } - } - } - - sort.Slice(secretsRows, func(i, j int) bool { - return secretsRows[i].SeverityNumValue > secretsRows[j].SeverityNumValue - }) - - return secretsRows -} - -func PrintSecretsTable(secrets []*sarif.Run, entitledForSecretsScan bool) error { - if entitledForSecretsScan { - secretsRows := prepareSecrets(secrets, true) - log.Output() - return coreutils.PrintTable(formats.ConvertToSecretsTableRow(secretsRows), "Secret Detection", - "✨ No secrets were found ✨", false) - } - return nil -} - -// Prepare iacs for all non-table formats (without style or emoji) -func PrepareIacs(iacs []*sarif.Run) []formats.SourceCodeRow { - return prepareIacs(iacs, false) -} - -func prepareIacs(iacs []*sarif.Run, isTable bool) []formats.SourceCodeRow { - var iacRows []formats.SourceCodeRow - for _, iacRun := range iacs { - for _, iacResult := range iacRun.Results { - scannerDescription := "" - if rule, err := iacRun.GetRuleById(*iacResult.RuleID); err == nil { - scannerDescription = sarifutils.GetRuleFullDescription(rule) - } - currSeverity, err := severityutils.ParseSeverity(sarifutils.GetResultLevel(iacResult), true) - if err != nil { - log.Warn(fmt.Sprintf("Failed to parse severity `%s` for iac result: %s", sarifutils.GetResultLevel(iacResult), *iacResult.RuleID)) - currSeverity = severityutils.Unknown - } - for _, location := range iacResult.Locations { - iacRows = append(iacRows, - formats.SourceCodeRow{ - SeverityDetails: severityutils.GetAsDetails(currSeverity, jasutils.Applicable, isTable), - Finding: sarifutils.GetResultMsgText(iacResult), - ScannerDescription: scannerDescription, - Location: formats.Location{ - File: sarifutils.GetRelativeLocationFileName(location, iacRun.Invocations), - StartLine: sarifutils.GetLocationStartLine(location), - StartColumn: sarifutils.GetLocationStartColumn(location), - EndLine: sarifutils.GetLocationEndLine(location), - EndColumn: sarifutils.GetLocationEndColumn(location), - Snippet: sarifutils.GetLocationSnippet(location), - }, - }, - ) - } - } - } - - sort.Slice(iacRows, func(i, j int) bool { - return iacRows[i].SeverityNumValue > iacRows[j].SeverityNumValue - }) - - return iacRows -} - -func PrintIacTable(iacs []*sarif.Run, entitledForIacScan bool) error { - if entitledForIacScan { - iacRows := prepareIacs(iacs, true) - log.Output() - return coreutils.PrintTable(formats.ConvertToIacOrSastTableRow(iacRows), "Infrastructure as Code Vulnerabilities", - "✨ No Infrastructure as Code vulnerabilities were found ✨", false) - } - return nil -} - -func PrepareSast(sasts []*sarif.Run) []formats.SourceCodeRow { - return prepareSast(sasts, false) -} - -func prepareSast(sasts []*sarif.Run, isTable bool) []formats.SourceCodeRow { - var sastRows []formats.SourceCodeRow - for _, sastRun := range sasts { - for _, sastResult := range sastRun.Results { - scannerDescription := "" - if rule, err := sastRun.GetRuleById(*sastResult.RuleID); err == nil { - scannerDescription = sarifutils.GetRuleFullDescription(rule) - } - currSeverity, err := severityutils.ParseSeverity(sarifutils.GetResultLevel(sastResult), true) - if err != nil { - log.Warn(fmt.Sprintf("Failed to parse severity `%s` for sast result: %s", sarifutils.GetResultLevel(sastResult), *sastResult.RuleID)) - currSeverity = severityutils.Unknown - } - for _, location := range sastResult.Locations { - codeFlows := sarifutils.GetLocationRelatedCodeFlowsFromResult(location, sastResult) - sastRows = append(sastRows, - formats.SourceCodeRow{ - SeverityDetails: severityutils.GetAsDetails(currSeverity, jasutils.Applicable, isTable), - ScannerDescription: scannerDescription, - Finding: sarifutils.GetResultMsgText(sastResult), - Location: formats.Location{ - File: sarifutils.GetRelativeLocationFileName(location, sastRun.Invocations), - StartLine: sarifutils.GetLocationStartLine(location), - StartColumn: sarifutils.GetLocationStartColumn(location), - EndLine: sarifutils.GetLocationEndLine(location), - EndColumn: sarifutils.GetLocationEndColumn(location), - Snippet: sarifutils.GetLocationSnippet(location), - }, - CodeFlow: codeFlowToLocationFlow(codeFlows, sastRun.Invocations, isTable), - }, - ) - } - } - } - - sort.Slice(sastRows, func(i, j int) bool { - return sastRows[i].SeverityNumValue > sastRows[j].SeverityNumValue - }) - - return sastRows -} - -func codeFlowToLocationFlow(flows []*sarif.CodeFlow, invocations []*sarif.Invocation, isTable bool) (flowRows [][]formats.Location) { - if isTable { - // Not displaying in table - return - } - for _, codeFlow := range flows { - for _, stackTrace := range codeFlow.ThreadFlows { - rowFlow := []formats.Location{} - for _, stackTraceEntry := range stackTrace.Locations { - rowFlow = append(rowFlow, formats.Location{ - File: sarifutils.GetRelativeLocationFileName(stackTraceEntry.Location, invocations), - StartLine: sarifutils.GetLocationStartLine(stackTraceEntry.Location), - StartColumn: sarifutils.GetLocationStartColumn(stackTraceEntry.Location), - EndLine: sarifutils.GetLocationEndLine(stackTraceEntry.Location), - EndColumn: sarifutils.GetLocationEndColumn(stackTraceEntry.Location), - Snippet: sarifutils.GetLocationSnippet(stackTraceEntry.Location), - }) - } - flowRows = append(flowRows, rowFlow) - } - } - return -} - -func PrintSastTable(sast []*sarif.Run, entitledForSastScan bool) error { - if entitledForSastScan { - sastRows := prepareSast(sast, true) - log.Output() - return coreutils.PrintTable(formats.ConvertToIacOrSastTableRow(sastRows), "Static Application Security Testing (SAST)", - "✨ No Static Application Security Testing vulnerabilities were found ✨", false) - } - return nil -} - -func convertJfrogResearchInformation(extendedInfo *services.ExtendedInformation) *formats.JfrogResearchInformation { - if extendedInfo == nil { - return nil - } - var severityReasons []formats.JfrogResearchSeverityReason - for _, severityReason := range extendedInfo.JfrogResearchSeverityReasons { - severityReasons = append(severityReasons, formats.JfrogResearchSeverityReason{ - Name: severityReason.Name, - Description: severityReason.Description, - IsPositive: severityReason.IsPositive, - }) - } - return &formats.JfrogResearchInformation{ - Summary: extendedInfo.ShortDescription, - Details: extendedInfo.FullDescription, - SeverityDetails: formats.SeverityDetails{Severity: extendedInfo.JfrogResearchSeverity}, - SeverityReasons: severityReasons, - Remediation: extendedInfo.Remediation, - } -} - -func splitComponents(impactedPackages map[string]services.Component) (impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes []string, fixedVersions [][]string, directComponents [][]formats.ComponentRow, impactPaths [][][]formats.ComponentRow, err error) { - if len(impactedPackages) == 0 { - err = errorutils.CheckErrorf("failed while parsing the response from Xray: violation doesn't have any components") - return - } - for currCompId, currComp := range impactedPackages { - currCompName, currCompVersion, currCompType := techutils.SplitComponentId(currCompId) - impactedPackagesNames = append(impactedPackagesNames, currCompName) - impactedPackagesVersions = append(impactedPackagesVersions, currCompVersion) - impactedPackagesTypes = append(impactedPackagesTypes, currCompType) - fixedVersions = append(fixedVersions, currComp.FixedVersions) - currDirectComponents, currImpactPaths := getDirectComponentsAndImpactPaths(currComp.ImpactPaths) - directComponents = append(directComponents, currDirectComponents) - impactPaths = append(impactPaths, currImpactPaths) - } - return -} - -// Gets a slice of the direct dependencies or packages of the scanned component, that depends on the vulnerable package, and converts the impact paths. -func getDirectComponentsAndImpactPaths(impactPaths [][]services.ImpactPathNode) (components []formats.ComponentRow, impactPathsRows [][]formats.ComponentRow) { - componentsMap := make(map[string]formats.ComponentRow) - - // The first node in the impact path is the scanned component itself. The second one is the direct dependency. - impactPathLevel := 1 - for _, impactPath := range impactPaths { - impactPathIndex := impactPathLevel - if len(impactPath) <= impactPathLevel { - impactPathIndex = len(impactPath) - 1 - } - componentId := impactPath[impactPathIndex].ComponentId - if _, exist := componentsMap[componentId]; !exist { - compName, compVersion, _ := techutils.SplitComponentId(componentId) - componentsMap[componentId] = formats.ComponentRow{Name: compName, Version: compVersion} - } - - // Convert the impact path - var compImpactPathRows []formats.ComponentRow - for _, pathNode := range impactPath { - nodeCompName, nodeCompVersion, _ := techutils.SplitComponentId(pathNode.ComponentId) - compImpactPathRows = append(compImpactPathRows, formats.ComponentRow{ - Name: nodeCompName, - Version: nodeCompVersion, - }) - } - impactPathsRows = append(impactPathsRows, compImpactPathRows) - } - - for _, row := range componentsMap { - components = append(components, row) - } - return -} - -type operationalRiskViolationReadableData struct { - isEol string - cadence string - commits string - committers string - eolMessage string - riskReason string - latestVersion string - newerVersions string -} - -func getOperationalRiskViolationReadableData(violation services.Violation) *operationalRiskViolationReadableData { - isEol, cadence, commits, committers, newerVersions, latestVersion := "N/A", "N/A", "N/A", "N/A", "N/A", "N/A" - if violation.IsEol != nil { - isEol = strconv.FormatBool(*violation.IsEol) - } - if violation.Cadence != nil { - cadence = strconv.FormatFloat(*violation.Cadence, 'f', -1, 64) - } - if violation.Committers != nil { - committers = strconv.FormatInt(int64(*violation.Committers), 10) - } - if violation.Commits != nil { - commits = strconv.FormatInt(*violation.Commits, 10) - } - if violation.NewerVersions != nil { - newerVersions = strconv.FormatInt(int64(*violation.NewerVersions), 10) - } - if violation.LatestVersion != "" { - latestVersion = violation.LatestVersion - } - return &operationalRiskViolationReadableData{ - isEol: isEol, - cadence: cadence, - commits: commits, - committers: committers, - eolMessage: violation.EolMessage, - riskReason: violation.RiskReason, - latestVersion: latestVersion, - newerVersions: newerVersions, - } -} - -// simplifyVulnerabilities returns a new slice of services.Vulnerability that contains only the unique vulnerabilities from the input slice -// The uniqueness of the vulnerabilities is determined by the GetUniqueKey function -func simplifyVulnerabilities(scanVulnerabilities []services.Vulnerability, multipleRoots bool) []services.Vulnerability { - var uniqueVulnerabilities = make(map[string]*services.Vulnerability) - for _, vulnerability := range scanVulnerabilities { - for vulnerableComponentId := range vulnerability.Components { - vulnerableDependency, vulnerableVersion, _ := techutils.SplitComponentId(vulnerableComponentId) - packageKey := GetUniqueKey(vulnerableDependency, vulnerableVersion, vulnerability.IssueId, len(vulnerability.Components[vulnerableComponentId].FixedVersions) > 0) - if uniqueVulnerability, exist := uniqueVulnerabilities[packageKey]; exist { - fixedVersions := appendUniqueFixVersions(uniqueVulnerability.Components[vulnerableComponentId].FixedVersions, vulnerability.Components[vulnerableComponentId].FixedVersions...) - impactPaths := appendUniqueImpactPaths(uniqueVulnerability.Components[vulnerableComponentId].ImpactPaths, vulnerability.Components[vulnerableComponentId].ImpactPaths, multipleRoots) - uniqueVulnerabilities[packageKey].Components[vulnerableComponentId] = services.Component{ - FixedVersions: fixedVersions, - ImpactPaths: impactPaths, - } - continue - } - uniqueVulnerabilities[packageKey] = &services.Vulnerability{ - Cves: vulnerability.Cves, - Severity: vulnerability.Severity, - Components: map[string]services.Component{vulnerableComponentId: vulnerability.Components[vulnerableComponentId]}, - IssueId: vulnerability.IssueId, - Technology: vulnerability.Technology, - ExtendedInformation: vulnerability.ExtendedInformation, - Summary: vulnerability.Summary, - } - } - } - // convert map to slice - result := make([]services.Vulnerability, 0, len(uniqueVulnerabilities)) - for _, v := range uniqueVulnerabilities { - result = append(result, *v) - } - return result -} - -// simplifyViolations returns a new slice of services.Violations that contains only the unique violations from the input slice -// The uniqueness of the violations is determined by the GetUniqueKey function -func simplifyViolations(scanViolations []services.Violation, multipleRoots bool) []services.Violation { - var uniqueViolations = make(map[string]*services.Violation) - for _, violation := range scanViolations { - for vulnerableComponentId := range violation.Components { - vulnerableDependency, vulnerableVersion, _ := techutils.SplitComponentId(vulnerableComponentId) - packageKey := GetUniqueKey(vulnerableDependency, vulnerableVersion, violation.IssueId, len(violation.Components[vulnerableComponentId].FixedVersions) > 0) - if uniqueVulnerability, exist := uniqueViolations[packageKey]; exist { - fixedVersions := appendUniqueFixVersions(uniqueVulnerability.Components[vulnerableComponentId].FixedVersions, violation.Components[vulnerableComponentId].FixedVersions...) - impactPaths := appendUniqueImpactPaths(uniqueVulnerability.Components[vulnerableComponentId].ImpactPaths, violation.Components[vulnerableComponentId].ImpactPaths, multipleRoots) - uniqueViolations[packageKey].Components[vulnerableComponentId] = services.Component{ - FixedVersions: fixedVersions, - ImpactPaths: impactPaths, - } - continue - } - uniqueViolations[packageKey] = &services.Violation{ - Summary: violation.Summary, - Severity: violation.Severity, - ViolationType: violation.ViolationType, - Components: map[string]services.Component{vulnerableComponentId: violation.Components[vulnerableComponentId]}, - WatchName: violation.WatchName, - IssueId: violation.IssueId, - Cves: violation.Cves, - LicenseKey: violation.LicenseKey, - LicenseName: violation.LicenseName, - Technology: violation.Technology, - } - } - } - // convert map to slice - result := make([]services.Violation, 0, len(uniqueViolations)) - for _, v := range uniqueViolations { - result = append(result, *v) - } - return result -} - -// appendImpactPathsWithoutDuplicates appends the elements of a source [][]ImpactPathNode struct to a target [][]ImpactPathNode, without adding any duplicate elements. -// This implementation uses the ComponentId field of the ImpactPathNode struct to check for duplicates, as it is guaranteed to be unique. -func appendUniqueImpactPaths(target [][]services.ImpactPathNode, source [][]services.ImpactPathNode, multipleRoots bool) [][]services.ImpactPathNode { - if multipleRoots { - return appendUniqueImpactPathsForMultipleRoots(target, source) - } - impactPathMap := make(map[string][]services.ImpactPathNode) - for _, path := range target { - // The first node component id is the key and the value is the whole path - key := getImpactPathKey(path) - impactPathMap[key] = path - } - - for _, path := range source { - key := getImpactPathKey(path) - if _, exists := impactPathMap[key]; !exists { - impactPathMap[key] = path - target = append(target, path) - } - } - return target -} - -// getImpactPathKey return a key that is used as a key to identify and deduplicate impact paths. -// If an impact path length is equal to directDependencyPathLength, then the direct dependency is the key, and it's in the directDependencyIndex place. -func getImpactPathKey(path []services.ImpactPathNode) string { - key := path[rootIndex].ComponentId - if len(path) == directDependencyPathLength { - key = path[directDependencyIndex].ComponentId - } - return key -} - -// appendUniqueImpactPathsForMultipleRoots appends the source impact path to the target impact path while avoiding duplicates. -// Specifically, it is designed for handling multiple root projects, such as Maven or Gradle, by comparing each pair of paths and identifying the path that is closest to the direct dependency. -func appendUniqueImpactPathsForMultipleRoots(target [][]services.ImpactPathNode, source [][]services.ImpactPathNode) [][]services.ImpactPathNode { - for targetPathIndex, targetPath := range target { - for sourcePathIndex, sourcePath := range source { - var subset []services.ImpactPathNode - if len(sourcePath) <= len(targetPath) { - subset = isImpactPathIsSubset(targetPath, sourcePath) - if len(subset) != 0 { - target[targetPathIndex] = subset - } - } else { - subset = isImpactPathIsSubset(sourcePath, targetPath) - if len(subset) != 0 { - source[sourcePathIndex] = subset - } - } - } - } - - return appendUniqueImpactPaths(target, source, false) -} - -// isImpactPathIsSubset checks if targetPath is a subset of sourcePath, and returns the subset if exists -func isImpactPathIsSubset(target []services.ImpactPathNode, source []services.ImpactPathNode) []services.ImpactPathNode { - var subsetImpactPath []services.ImpactPathNode - impactPathNodesMap := make(map[string]bool) - for _, node := range target { - impactPathNodesMap[node.ComponentId] = true - } - - for _, node := range source { - if impactPathNodesMap[node.ComponentId] { - subsetImpactPath = append(subsetImpactPath, node) - } - } - - if len(subsetImpactPath) == len(target) || len(subsetImpactPath) == len(source) { - return subsetImpactPath - } - return []services.ImpactPathNode{} -} - -// appendUniqueFixVersions returns a new slice of strings that contains elements from both input slices without duplicates -func appendUniqueFixVersions(targetFixVersions []string, sourceFixVersions ...string) []string { - fixVersionsSet := datastructures.MakeSet[string]() - var result []string - for _, fixVersion := range sourceFixVersions { - fixVersionsSet.Add(fixVersion) - result = append(result, fixVersion) - } - - for _, fixVersion := range targetFixVersions { - if exist := fixVersionsSet.Exists(fixVersion); !exist { - result = append(result, fixVersion) - } - } - return result -} - -// GetUniqueKey returns a unique string key of format "vulnerableDependency:vulnerableVersion:xrayID:fixVersionExist" -func GetUniqueKey(vulnerableDependency, vulnerableVersion, xrayID string, fixVersionExist bool) string { - return strings.Join([]string{vulnerableDependency, vulnerableVersion, xrayID, strconv.FormatBool(fixVersionExist)}, ":") -} - -func convertCves(cves []services.Cve) []formats.CveRow { - var cveRows []formats.CveRow - for _, cveObj := range cves { - cveRows = append(cveRows, formats.CveRow{Id: cveObj.Id, CvssV2: cveObj.CvssV2Score, CvssV3: cveObj.CvssV3Score}) - } - return cveRows -} - -func getApplicableCveStatus(entitledForJas bool, applicabilityScanResults []*sarif.Run, cves []formats.CveRow) jasutils.ApplicabilityStatus { - if !entitledForJas || len(applicabilityScanResults) == 0 { - return jasutils.NotScanned - } - if len(cves) == 0 { - return jasutils.NotCovered - } - var applicableStatuses []jasutils.ApplicabilityStatus - for _, cve := range cves { - if cve.Applicability != nil { - applicableStatuses = append(applicableStatuses, jasutils.ApplicabilityStatus(cve.Applicability.Status)) - } - } - return getFinalApplicabilityStatus(applicableStatuses) -} - -func getCveApplicabilityField(cveId string, applicabilityScanResults []*sarif.Run, components map[string]services.Component) *formats.Applicability { - if len(applicabilityScanResults) == 0 { - return nil - } - - applicability := formats.Applicability{} - resultFound := false - var applicabilityStatuses []jasutils.ApplicabilityStatus - for _, applicabilityRun := range applicabilityScanResults { - if rule, _ := applicabilityRun.GetRuleById(jasutils.CveToApplicabilityRuleId(cveId)); rule != nil { - applicability.ScannerDescription = sarifutils.GetRuleFullDescription(rule) - status := getApplicabilityStatusFromRule(rule) - if status != "" { - applicabilityStatuses = append(applicabilityStatuses, status) - } - } - result, _ := applicabilityRun.GetResultByRuleId(jasutils.CveToApplicabilityRuleId(cveId)) - if result == nil { - continue - } - resultFound = true - // Add new evidences from locations - for _, location := range result.Locations { - fileName := sarifutils.GetRelativeLocationFileName(location, applicabilityRun.Invocations) - if shouldDisqualifyEvidence(components, fileName) { - continue - } - applicability.Evidence = append(applicability.Evidence, formats.Evidence{ - Location: formats.Location{ - File: fileName, - StartLine: sarifutils.GetLocationStartLine(location), - StartColumn: sarifutils.GetLocationStartColumn(location), - EndLine: sarifutils.GetLocationEndLine(location), - EndColumn: sarifutils.GetLocationEndColumn(location), - Snippet: sarifutils.GetLocationSnippet(location), - }, - Reason: sarifutils.GetResultMsgText(result), - }) - } - } - switch { - case len(applicabilityStatuses) > 0: - applicability.Status = getFinalApplicabilityStatus(applicabilityStatuses).String() - case !resultFound: - applicability.Status = jasutils.ApplicabilityUndetermined.String() - case len(applicability.Evidence) == 0: - applicability.Status = jasutils.NotApplicable.String() - default: - applicability.Status = jasutils.Applicable.String() - } - return &applicability -} - -func printApplicabilityCveValue(applicabilityStatus jasutils.ApplicabilityStatus, isTable bool) string { - if isTable && (log.IsStdOutTerminal() && log.IsColorsSupported() || os.Getenv("GITLAB_CI") != "") { - if applicabilityStatus == jasutils.Applicable { - return color.New(color.Red).Render(applicabilityStatus) - } else if applicabilityStatus == jasutils.NotApplicable { - return color.New(color.Green).Render(applicabilityStatus) - } - } - return applicabilityStatus.String() -} - -// Relevant only when "third-party-contextual-analysis" flag is on, -// which mean we scan the environment folders as well (node_modules for example...) -// When a certain package is reported applicable, and the evidence found -// is inside the source code of the same package, we should disqualify it. -// -// For example, -// Cve applicability was found inside the 'mquery' package. -// filePath = myProject/node_modules/mquery/badCode.js , disqualify = True. -// Disqualify the above evidence, as the reported applicability is used inside its own package. -// -// filePath = myProject/node_modules/mpath/badCode.js , disqualify = False. -// Found use of a badCode inside the node_modules from a different package, report applicable. -func shouldDisqualifyEvidence(components map[string]services.Component, evidenceFilePath string) (disqualify bool) { - for key := range components { - if !strings.HasPrefix(key, NpmPackageTypeIdentifier) { - return - } - dependencyName := extractDependencyNameFromComponent(key, NpmPackageTypeIdentifier) - // Check both Unix & Windows paths. - if strings.Contains(evidenceFilePath, nodeModules+"/"+dependencyName) || strings.Contains(evidenceFilePath, filepath.Join(nodeModules, dependencyName)) { - return true - } - } - return -} - -func extractDependencyNameFromComponent(key string, techIdentifier string) (dependencyName string) { - packageAndVersion := strings.TrimPrefix(key, techIdentifier) - split := strings.Split(packageAndVersion, ":") - if len(split) < 2 { - return - } - dependencyName = split[0] - return -} - -func getApplicabilityStatusFromRule(rule *sarif.ReportingDescriptor) jasutils.ApplicabilityStatus { - if rule.Properties["applicability"] != nil { - status, ok := rule.Properties["applicability"].(string) - if !ok { - log.Debug(fmt.Sprintf("Failed to get applicability status from rule properties for rule_id %s", rule.ID)) - } - switch status { - case "not_covered": - return jasutils.NotCovered - case "undetermined": - return jasutils.ApplicabilityUndetermined - case "not_applicable": - return jasutils.NotApplicable - case "applicable": - return jasutils.Applicable - } - } - return "" -} - -// If we don't get any statues it means the applicability scanner didn't run -> final value is not scanned -// If at least one cve is applicable -> final value is applicable -// Else if at least one cve is undetermined -> final value is undetermined -// Else if all cves are not covered -> final value is not covered -// Else (case when all cves aren't applicable) -> final value is not applicable -func getFinalApplicabilityStatus(applicabilityStatuses []jasutils.ApplicabilityStatus) jasutils.ApplicabilityStatus { - if len(applicabilityStatuses) == 0 { - return jasutils.NotScanned - } - foundUndetermined := false - foundNotCovered := false - for _, status := range applicabilityStatuses { - if status == jasutils.Applicable { - return jasutils.Applicable - } - if status == jasutils.ApplicabilityUndetermined { - foundUndetermined = true - } - if status == jasutils.NotCovered { - foundNotCovered = true - } - } - if foundUndetermined { - return jasutils.ApplicabilityUndetermined - } - if foundNotCovered { - return jasutils.NotCovered - } - return jasutils.NotApplicable -} diff --git a/utils/resultstable_test.go b/utils/resultstable_test.go deleted file mode 100644 index 3de0a309..00000000 --- a/utils/resultstable_test.go +++ /dev/null @@ -1,1111 +0,0 @@ -package utils - -import ( - "fmt" - "testing" - - "github.com/jfrog/jfrog-cli-security/utils/formats" - "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" - "github.com/jfrog/jfrog-cli-security/utils/jasutils" - "github.com/jfrog/jfrog-cli-security/utils/techutils" - "github.com/owenrumney/go-sarif/v2/sarif" - - "github.com/jfrog/jfrog-client-go/xray/services" - "github.com/stretchr/testify/assert" -) - -// The test only checks cases of returning an error in case of a violation with FailBuild == true -func TestPrintViolationsTable(t *testing.T) { - components := map[string]services.Component{"gav://antparent:ant:1.6.5": {}} - tests := []struct { - violations []services.Violation - expectedError bool - }{ - {[]services.Violation{{Components: components, FailBuild: false}, {Components: components, FailBuild: false}, {Components: components, FailBuild: false}}, false}, - {[]services.Violation{{Components: components, FailBuild: false}, {Components: components, FailBuild: true}, {Components: components, FailBuild: false}}, true}, - {[]services.Violation{{Components: components, FailBuild: true}, {Components: components, FailBuild: true}, {Components: components, FailBuild: true}}, true}, - } - - for _, test := range tests { - err := PrintViolationsTable(test.violations, NewAuditResults(), false, true, services.Binary) - assert.NoError(t, err) - if CheckIfFailBuild([]services.ScanResponse{{Violations: test.violations}}) { - err = NewFailBuildError() - } - assert.Equal(t, test.expectedError, err != nil) - } -} - -func TestSplitComponentId(t *testing.T) { - tests := []struct { - componentId string - expectedCompName string - expectedCompVersion string - expectedCompType string - }{ - {"gav://antparent:ant:1.6.5", "antparent:ant", "1.6.5", "Maven"}, - {"docker://jfrog/artifactory-oss:latest", "jfrog/artifactory-oss", "latest", "Docker"}, - {"rpm://7:rpm-python:7:4.11.3-43.el7", "rpm-python", "7:4.11.3-43.el7", "RPM"}, - {"rpm://rpm-python:7:4.11.3-43.el7", "rpm-python", "7:4.11.3-43.el7", "RPM"}, - {"deb://ubuntu:trustee:acl:2.2.49-2", "ubuntu:trustee:acl", "2.2.49-2", "Debian"}, - {"nuget://log4net:9.0.1", "log4net", "9.0.1", "NuGet"}, - {"generic://sha256:244fd47e07d1004f0aed9c156aa09083c82bf8944eceb67c946ff7430510a77b/foo.jar", "foo.jar", "", "Generic"}, - {"npm://mocha:2.4.5", "mocha", "2.4.5", "npm"}, - {"pip://raven:5.13.0", "raven", "5.13.0", "Python"}, - {"composer://nunomaduro/collision:1.1", "nunomaduro/collision", "1.1", "Composer"}, - {"go://github.com/ethereum/go-ethereum:1.8.2", "github.com/ethereum/go-ethereum", "1.8.2", "Go"}, - {"alpine://3.7:htop:2.0.2-r0", "3.7:htop", "2.0.2-r0", "Alpine"}, - {"invalid-component-id:1.0.0", "invalid-component-id:1.0.0", "", ""}, - } - - for _, test := range tests { - actualCompName, actualCompVersion, actualCompType := techutils.SplitComponentId(test.componentId) - assert.Equal(t, test.expectedCompName, actualCompName) - assert.Equal(t, test.expectedCompVersion, actualCompVersion) - assert.Equal(t, test.expectedCompType, actualCompType) - } -} - -func TestGetDirectComponents(t *testing.T) { - tests := []struct { - impactPaths [][]services.ImpactPathNode - expectedComponentRows []formats.ComponentRow - expectedConvImpactPaths [][]formats.ComponentRow - }{ - {[][]services.ImpactPathNode{{services.ImpactPathNode{ComponentId: "gav://jfrog:pack:1.2.3"}}}, []formats.ComponentRow{{Name: "jfrog:pack", Version: "1.2.3"}}, [][]formats.ComponentRow{{{Name: "jfrog:pack", Version: "1.2.3"}}}}, - {[][]services.ImpactPathNode{{services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack2:1.2.3"}}}, []formats.ComponentRow{{Name: "jfrog:pack2", Version: "1.2.3"}}, [][]formats.ComponentRow{{{Name: "jfrog:pack1", Version: "1.2.3"}, {Name: "jfrog:pack2", Version: "1.2.3"}}}}, - {[][]services.ImpactPathNode{{services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack21:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack3:1.2.3"}}, {services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack22:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack3:1.2.3"}}}, []formats.ComponentRow{{Name: "jfrog:pack21", Version: "1.2.3"}, {Name: "jfrog:pack22", Version: "1.2.3"}}, [][]formats.ComponentRow{{{Name: "jfrog:pack1", Version: "1.2.3"}, {Name: "jfrog:pack21", Version: "1.2.3"}, {Name: "jfrog:pack3", Version: "1.2.3"}}, {{Name: "jfrog:pack1", Version: "1.2.3"}, {Name: "jfrog:pack22", Version: "1.2.3"}, {Name: "jfrog:pack3", Version: "1.2.3"}}}}, - } - - for _, test := range tests { - actualComponentRows, actualConvImpactPaths := getDirectComponentsAndImpactPaths(test.impactPaths) - assert.ElementsMatch(t, test.expectedComponentRows, actualComponentRows) - assert.ElementsMatch(t, test.expectedConvImpactPaths, actualConvImpactPaths) - } -} - -func TestGetOperationalRiskReadableData(t *testing.T) { - tests := []struct { - violation services.Violation - expectedResults *operationalRiskViolationReadableData - }{ - { - services.Violation{IsEol: nil, LatestVersion: "", NewerVersions: nil, - Cadence: nil, Commits: nil, Committers: nil, RiskReason: "", EolMessage: ""}, - &operationalRiskViolationReadableData{"N/A", "N/A", "N/A", "N/A", "", "", "N/A", "N/A"}, - }, - { - services.Violation{IsEol: newBoolPtr(true), LatestVersion: "1.2.3", NewerVersions: newIntPtr(5), - Cadence: newFloat64Ptr(3.5), Commits: newInt64Ptr(55), Committers: newIntPtr(10), EolMessage: "no maintainers", RiskReason: "EOL"}, - &operationalRiskViolationReadableData{"true", "3.5", "55", "10", "no maintainers", "EOL", "1.2.3", "5"}, - }, - } - - for _, test := range tests { - results := getOperationalRiskViolationReadableData(test.violation) - assert.Equal(t, test.expectedResults, results) - } -} - -func TestIsImpactPathIsSubset(t *testing.T) { - testCases := []struct { - name string - target, source, expectedResult []services.ImpactPathNode - }{ - {"subset found in both target and source", - []services.ImpactPathNode{{ComponentId: "B"}, {ComponentId: "C"}}, - []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "C"}}, - []services.ImpactPathNode{{ComponentId: "B"}, {ComponentId: "C"}}, - }, - {"subset not found in both target and source", - []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "D"}}, - []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "C"}}, - []services.ImpactPathNode{}, - }, - {"target and source are identical", - []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}}, - []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}}, - []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}}, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - result := isImpactPathIsSubset(tc.target, tc.source) - assert.Equal(t, tc.expectedResult, result) - }) - } -} - -func TestAppendUniqueFixVersions(t *testing.T) { - testCases := []struct { - targetFixVersions []string - sourceFixVersions []string - expectedResult []string - }{ - { - targetFixVersions: []string{"1.0", "1.1"}, - sourceFixVersions: []string{"2.0", "2.1"}, - expectedResult: []string{"1.0", "1.1", "2.0", "2.1"}, - }, - { - targetFixVersions: []string{"1.0", "1.1"}, - sourceFixVersions: []string{"1.1", "2.0"}, - expectedResult: []string{"1.0", "1.1", "2.0"}, - }, - { - targetFixVersions: []string{}, - sourceFixVersions: []string{"1.0", "1.1"}, - expectedResult: []string{"1.0", "1.1"}, - }, - { - targetFixVersions: []string{"1.0", "1.1"}, - sourceFixVersions: []string{}, - expectedResult: []string{"1.0", "1.1"}, - }, - } - - for _, tc := range testCases { - t.Run(fmt.Sprintf("target:%v, source:%v", tc.targetFixVersions, tc.sourceFixVersions), func(t *testing.T) { - result := appendUniqueFixVersions(tc.targetFixVersions, tc.sourceFixVersions...) - assert.ElementsMatch(t, tc.expectedResult, result) - }) - } -} - -func TestGetUniqueKey(t *testing.T) { - vulnerableDependency := "test-dependency" - vulnerableVersion := "1.0" - expectedKey := "test-dependency:1.0:XRAY-12234:true" - key := GetUniqueKey(vulnerableDependency, vulnerableVersion, "XRAY-12234", true) - assert.Equal(t, expectedKey, key) - - expectedKey = "test-dependency:1.0:XRAY-12143:false" - key = GetUniqueKey(vulnerableDependency, vulnerableVersion, "XRAY-12143", false) - assert.Equal(t, expectedKey, key) -} - -func TestAppendUniqueImpactPathsForMultipleRoots(t *testing.T) { - testCases := []struct { - name string - target [][]services.ImpactPathNode - source [][]services.ImpactPathNode - expectedResult [][]services.ImpactPathNode - }{ - { - name: "subset is found in both target and source", - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "C"}}, - {{ComponentId: "D"}, {ComponentId: "E"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "B"}, {ComponentId: "C"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - expectedResult: [][]services.ImpactPathNode{ - {{ComponentId: "B"}, {ComponentId: "C"}}, - {{ComponentId: "D"}, {ComponentId: "E"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - }, - { - name: "subset is not found in both target and source", - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "C"}}, - {{ComponentId: "D"}, {ComponentId: "E"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "B"}, {ComponentId: "C"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - expectedResult: [][]services.ImpactPathNode{ - {{ComponentId: "B"}, {ComponentId: "C"}}, - {{ComponentId: "D"}, {ComponentId: "E"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - }, - { - name: "target slice is empty", - target: [][]services.ImpactPathNode{}, - source: [][]services.ImpactPathNode{ - {{ComponentId: "E"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - expectedResult: [][]services.ImpactPathNode{ - {{ComponentId: "E"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - }, - { - name: "source slice is empty", - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - source: [][]services.ImpactPathNode{}, - expectedResult: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - }, - { - name: "target and source slices are identical", - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - expectedResult: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - }, - { - name: "target and source slices contain multiple subsets", - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "E"}}, - {{ComponentId: "C"}, {ComponentId: "D"}, {ComponentId: "F"}}, - {{ComponentId: "G"}, {ComponentId: "H"}}, - }, - expectedResult: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - {{ComponentId: "G"}, {ComponentId: "H"}}, - }, - }, - } - - for _, test := range testCases { - t.Run(test.name, func(t *testing.T) { - assert.Equal(t, test.expectedResult, appendUniqueImpactPathsForMultipleRoots(test.target, test.source)) - }) - } -} - -func TestGetImpactPathKey(t *testing.T) { - testCases := []struct { - path []services.ImpactPathNode - expectedKey string - }{ - { - path: []services.ImpactPathNode{ - {ComponentId: "A"}, - {ComponentId: "B"}, - }, - expectedKey: "B", - }, - { - path: []services.ImpactPathNode{ - {ComponentId: "A"}, - }, - expectedKey: "A", - }, - } - - for _, test := range testCases { - key := getImpactPathKey(test.path) - assert.Equal(t, test.expectedKey, key) - } -} - -func TestAppendUniqueImpactPaths(t *testing.T) { - testCases := []struct { - name string - multipleRoots bool - target [][]services.ImpactPathNode - source [][]services.ImpactPathNode - expected [][]services.ImpactPathNode - }{ - { - name: "Test case 1: Unique impact paths found", - multipleRoots: false, - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}}, - {{ComponentId: "B"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "C"}}, - {{ComponentId: "D"}}, - }, - expected: [][]services.ImpactPathNode{ - {{ComponentId: "A"}}, - {{ComponentId: "B"}}, - {{ComponentId: "C"}}, - {{ComponentId: "D"}}, - }, - }, - { - name: "Test case 2: No unique impact paths found", - multipleRoots: false, - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}}, - {{ComponentId: "B"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "A"}}, - {{ComponentId: "B"}}, - }, - expected: [][]services.ImpactPathNode{ - {{ComponentId: "A"}}, - {{ComponentId: "B"}}, - }, - }, - { - name: "Test case 3: paths in source are not in target", - multipleRoots: false, - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "E"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - expected: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - {{ComponentId: "E"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - }, - { - name: "Test case 4: paths in source are already in target", - multipleRoots: false, - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - expected: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - result := appendUniqueImpactPaths(tc.target, tc.source, tc.multipleRoots) - assert.Equal(t, tc.expected, result) - }) - } -} - -func TestGetApplicableCveValue(t *testing.T) { - testCases := []struct { - name string - scanResults *ExtendedScanResults - cves []services.Cve - expectedResult jasutils.ApplicabilityStatus - expectedCves []formats.CveRow - }{ - { - name: "not entitled for jas", - scanResults: &ExtendedScanResults{EntitledForJas: false}, - expectedResult: jasutils.NotScanned, - }, - { - name: "no cves", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateResultWithOneLocation("fileName1", 0, 1, 0, 0, "snippet1", "applic_testCve1", "info"), - sarifutils.CreateDummyPassingResult("applic_testCve2"), - ), - }, - EntitledForJas: true, - }, - cves: nil, - expectedResult: jasutils.NotCovered, - expectedCves: nil, - }, - { - name: "applicable cve", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateDummyPassingResult("applic_testCve1"), - sarifutils.CreateResultWithOneLocation("fileName2", 1, 0, 0, 0, "snippet2", "applic_testCve2", "warning"), - ), - }, - EntitledForJas: true, - }, - cves: []services.Cve{{Id: "testCve2"}}, - expectedResult: jasutils.Applicable, - expectedCves: []formats.CveRow{{Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.Applicable.String()}}}, - }, - { - name: "undetermined cve", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateDummyPassingResult("applic_testCve1"), - sarifutils.CreateResultWithOneLocation("fileName3", 0, 1, 0, 0, "snippet3", "applic_testCve2", "info"), - ), - }, - EntitledForJas: true, - }, - cves: []services.Cve{{Id: "testCve3"}}, - expectedResult: jasutils.ApplicabilityUndetermined, - expectedCves: []formats.CveRow{{Id: "testCve3"}}, - }, - { - name: "not applicable cve", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateDummyPassingResult("applic_testCve1"), - sarifutils.CreateDummyPassingResult("applic_testCve2"), - ), - }, - EntitledForJas: true, - }, - cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - expectedResult: jasutils.NotApplicable, - expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}, {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}}, - }, - { - name: "applicable and not applicable cves", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateDummyPassingResult("applic_testCve1"), - sarifutils.CreateResultWithOneLocation("fileName4", 1, 0, 0, 0, "snippet", "applic_testCve2", "warning"), - ), - }, - EntitledForJas: true, - }, - cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - expectedResult: jasutils.Applicable, - expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}, {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.Applicable.String()}}}, - }, - { - name: "undetermined and not applicable cves", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyPassingResult("applic_testCve1")), - }, - EntitledForJas: true}, - cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - expectedResult: jasutils.ApplicabilityUndetermined, - expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}, {Id: "testCve2"}}, - }, - { - name: "new scan statuses - applicable wins all statuses", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", sarifutils.CreateDummyPassingResult("applic_testCve1")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_testCve2")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve3")), - }, - EntitledForJas: true}, - cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}, {Id: "testCve3"}}, - expectedResult: jasutils.Applicable, - expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.Applicable.String()}}, - {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}, - {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.NotCovered.String()}}, - }, - }, - { - name: "new scan statuses - not covered wins not applicable", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve1")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_testCve2")), - }, - EntitledForJas: true}, - cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - expectedResult: jasutils.NotCovered, - expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.NotCovered.String()}}, - {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}, - }, - }, - { - name: "new scan statuses - undetermined wins not covered", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve1")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "undetermined", sarifutils.CreateDummyPassingResult("applic_testCve2")), - }, - EntitledForJas: true}, - cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - expectedResult: jasutils.ApplicabilityUndetermined, - expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.NotCovered.String()}}, - {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.ApplicabilityUndetermined.String()}}, - }, - }, - } - - for _, testCase := range testCases { - cves := convertCves(testCase.cves) - for i := range cves { - cves[i].Applicability = getCveApplicabilityField(cves[i].Id, testCase.scanResults.ApplicabilityScanResults, nil) - } - applicableValue := getApplicableCveStatus(testCase.scanResults.EntitledForJas, testCase.scanResults.ApplicabilityScanResults, cves) - assert.Equal(t, testCase.expectedResult, applicableValue) - if assert.True(t, len(testCase.expectedCves) == len(cves)) { - for i := range cves { - if testCase.expectedCves[i].Applicability != nil && assert.NotNil(t, cves[i].Applicability) { - assert.Equal(t, testCase.expectedCves[i].Applicability.Status, cves[i].Applicability.Status) - } - } - } - } -} - -func TestSortVulnerabilityOrViolationRows(t *testing.T) { - testCases := []struct { - name string - rows []formats.VulnerabilityOrViolationRow - expectedOrder []string - }{ - { - name: "Sort by severity with different severity values", - rows: []formats.VulnerabilityOrViolationRow{ - { - Summary: "Summary 1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "High", - SeverityNumValue: 9, - }, - ImpactedDependencyName: "Dependency 1", - ImpactedDependencyVersion: "1.0.0", - }, - FixedVersions: []string{}, - }, - { - Summary: "Summary 2", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "Critical", - SeverityNumValue: 12, - }, - ImpactedDependencyName: "Dependency 2", - ImpactedDependencyVersion: "2.0.0", - }, - FixedVersions: []string{"1.0.0"}, - }, - { - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "Medium", - SeverityNumValue: 6, - }, - ImpactedDependencyName: "Dependency 3", - ImpactedDependencyVersion: "3.0.0", - }, - Summary: "Summary 3", - FixedVersions: []string{}, - }, - }, - expectedOrder: []string{"Dependency 2", "Dependency 1", "Dependency 3"}, - }, - { - name: "Sort by severity with same severity values, but different fixed versions", - rows: []formats.VulnerabilityOrViolationRow{ - { - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "Critical", - SeverityNumValue: 12, - }, - ImpactedDependencyName: "Dependency 1", - ImpactedDependencyVersion: "1.0.0", - }, - Summary: "Summary 1", - FixedVersions: []string{"1.0.0"}, - }, - { - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "Critical", - SeverityNumValue: 12, - }, - ImpactedDependencyName: "Dependency 2", - ImpactedDependencyVersion: "2.0.0", - }, - Summary: "Summary 2", - FixedVersions: []string{}, - }, - }, - expectedOrder: []string{"Dependency 1", "Dependency 2"}, - }, - { - name: "Sort by severity with same severity values different applicability", - rows: []formats.VulnerabilityOrViolationRow{ - { - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "Critical", - SeverityNumValue: 13, - }, - ImpactedDependencyName: "Dependency 1", - ImpactedDependencyVersion: "1.0.0", - }, - Summary: "Summary 1", - Applicable: jasutils.Applicable.String(), - FixedVersions: []string{"1.0.0"}, - }, - { - Summary: "Summary 2", - Applicable: jasutils.NotApplicable.String(), - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "Critical", - SeverityNumValue: 11, - }, - ImpactedDependencyName: "Dependency 2", - ImpactedDependencyVersion: "2.0.0", - }, - }, - { - Summary: "Summary 3", - Applicable: jasutils.ApplicabilityUndetermined.String(), - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "Critical", - SeverityNumValue: 12, - }, - ImpactedDependencyName: "Dependency 3", - ImpactedDependencyVersion: "2.0.0", - }, - }, - }, - expectedOrder: []string{"Dependency 1", "Dependency 3", "Dependency 2"}, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - sortVulnerabilityOrViolationRows(tc.rows) - - for i, row := range tc.rows { - assert.Equal(t, tc.expectedOrder[i], row.ImpactedDependencyName) - } - }) - } -} - -func TestShouldDisqualifyEvidence(t *testing.T) { - testCases := []struct { - name string - component map[string]services.Component - filePath string - disqualify bool - }{ - { - name: "package folders", - component: map[string]services.Component{"npm://protobufjs:6.11.2": {}}, - filePath: "file:///Users/jfrog/test/node_modules/protobufjs/src/badCode.js", - disqualify: true, - }, { - name: "nested folders", - component: map[string]services.Component{"npm://protobufjs:6.11.2": {}}, - filePath: "file:///Users/jfrog/test/node_modules/someDep/node_modules/protobufjs/src/badCode.js", - disqualify: true, - }, { - name: "applicability in node modules", - component: map[string]services.Component{"npm://protobufjs:6.11.2": {}}, - filePath: "file:///Users/jfrog/test/node_modules/mquery/src/badCode.js", - disqualify: false, - }, { - // Only npm supported - name: "not npm", - component: map[string]services.Component{"yarn://protobufjs:6.11.2": {}}, - filePath: "file:///Users/jfrog/test/node_modules/protobufjs/src/badCode.js", - disqualify: false, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, tc.disqualify, shouldDisqualifyEvidence(tc.component, tc.filePath)) - }) - } -} - -func TestPrepareIac(t *testing.T) { - testCases := []struct { - name string - input []*sarif.Run - expectedOutput []formats.SourceCodeRow - }{ - { - name: "No Iac run", - input: []*sarif.Run{}, - expectedOutput: []formats.SourceCodeRow{}, - }, - { - name: "Prepare Iac run - no results", - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults(), - }, - expectedOutput: []formats.SourceCodeRow{}, - }, - { - name: "Prepare Iac run - with results", - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateResultWithLocations("iac finding", "rule1", "info", - sarifutils.CreateLocation("file://wd/file", 1, 2, 3, 4, "snippet"), - sarifutils.CreateLocation("file://wd/file2", 5, 6, 7, 8, "other-snippet"), - ), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("wd")), - }), - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateResultWithLocations("other iac finding", "rule2", "error", - sarifutils.CreateLocation("file://wd2/file3", 1, 2, 3, 4, "snippet"), - ), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("wd2")), - }), - }, - expectedOutput: []formats.SourceCodeRow{ - { - SeverityDetails: formats.SeverityDetails{ - Severity: "High", - SeverityNumValue: 17, - }, - Finding: "other iac finding", - Location: formats.Location{ - File: "file3", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "snippet", - }, - }, - { - SeverityDetails: formats.SeverityDetails{ - Severity: "Medium", - SeverityNumValue: 14, - }, - Finding: "iac finding", - Location: formats.Location{ - File: "file", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "snippet", - }, - }, - { - SeverityDetails: formats.SeverityDetails{ - Severity: "Medium", - SeverityNumValue: 14, - }, - Finding: "iac finding", - Location: formats.Location{ - File: "file2", - StartLine: 5, - StartColumn: 6, - EndLine: 7, - EndColumn: 8, - Snippet: "other-snippet", - }, - }, - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.ElementsMatch(t, tc.expectedOutput, prepareIacs(tc.input, false)) - }) - } -} - -func TestPrepareSecrets(t *testing.T) { - testCases := []struct { - name string - input []*sarif.Run - expectedOutput []formats.SourceCodeRow - }{ - { - name: "No Secret run", - input: []*sarif.Run{}, - expectedOutput: []formats.SourceCodeRow{}, - }, - { - name: "Prepare Secret run - no results", - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults(), - }, - expectedOutput: []formats.SourceCodeRow{}, - }, - { - name: "Prepare Secret run - with results", - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateResultWithLocations("secret finding", "rule1", "info", - sarifutils.CreateLocation("file://wd/file", 1, 2, 3, 4, "some-secret-snippet"), - sarifutils.CreateLocation("file://wd/file2", 5, 6, 7, 8, "other-secret-snippet"), - ), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("wd")), - }), - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateResultWithLocations("other secret finding", "rule2", "note", - sarifutils.CreateLocation("file://wd2/file3", 1, 2, 3, 4, "some-secret-snippet"), - ), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("wd2")), - }), - }, - expectedOutput: []formats.SourceCodeRow{ - { - SeverityDetails: formats.SeverityDetails{ - Severity: "Low", - SeverityNumValue: 11, - }, - Finding: "other secret finding", - Location: formats.Location{ - File: "file3", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "some-secret-snippet", - }, - }, - { - SeverityDetails: formats.SeverityDetails{ - Severity: "Medium", - SeverityNumValue: 14, - }, - Finding: "secret finding", - Location: formats.Location{ - File: "file", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "some-secret-snippet", - }, - }, - { - SeverityDetails: formats.SeverityDetails{ - Severity: "Medium", - SeverityNumValue: 14, - }, - Finding: "secret finding", - Location: formats.Location{ - File: "file2", - StartLine: 5, - StartColumn: 6, - EndLine: 7, - EndColumn: 8, - Snippet: "other-secret-snippet", - }, - }, - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.ElementsMatch(t, tc.expectedOutput, prepareSecrets(tc.input, false)) - }) - } -} - -func TestPrepareSast(t *testing.T) { - testCases := []struct { - name string - input []*sarif.Run - expectedOutput []formats.SourceCodeRow - }{ - { - name: "No Sast run", - input: []*sarif.Run{}, - expectedOutput: []formats.SourceCodeRow{}, - }, - { - name: "Prepare Sast run - no results", - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults(), - }, - expectedOutput: []formats.SourceCodeRow{}, - }, - { - name: "Prepare Sast run - with results", - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateResultWithLocations("sast finding", "rule1", "info", - sarifutils.CreateLocation("file://wd/file", 1, 2, 3, 4, "snippet"), - sarifutils.CreateLocation("file://wd/file2", 5, 6, 7, 8, "other-snippet"), - ).WithCodeFlows([]*sarif.CodeFlow{ - sarifutils.CreateCodeFlow(sarifutils.CreateThreadFlow( - sarifutils.CreateLocation("file://wd/file2", 0, 2, 0, 2, "snippetA"), - sarifutils.CreateLocation("file://wd/file", 1, 2, 3, 4, "snippet"), - )), - sarifutils.CreateCodeFlow(sarifutils.CreateThreadFlow( - sarifutils.CreateLocation("file://wd/file4", 1, 0, 1, 8, "snippetB"), - sarifutils.CreateLocation("file://wd/file", 1, 2, 3, 4, "snippet"), - )), - }), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("wd")), - }), - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateResultWithLocations("other sast finding", "rule2", "error", - sarifutils.CreateLocation("file://wd2/file3", 1, 2, 3, 4, "snippet"), - ), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("wd2")), - }), - }, - expectedOutput: []formats.SourceCodeRow{ - { - SeverityDetails: formats.SeverityDetails{ - Severity: "High", - SeverityNumValue: 17, - }, - Finding: "other sast finding", - Location: formats.Location{ - File: "file3", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "snippet", - }, - }, - { - SeverityDetails: formats.SeverityDetails{ - Severity: "Medium", - SeverityNumValue: 14, - }, - Finding: "sast finding", - Location: formats.Location{ - File: "file", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "snippet", - }, - CodeFlow: [][]formats.Location{ - { - { - File: "file2", - StartLine: 0, - StartColumn: 2, - EndLine: 0, - EndColumn: 2, - Snippet: "snippetA", - }, - { - File: "file", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "snippet", - }, - }, - { - { - File: "file4", - StartLine: 1, - StartColumn: 0, - EndLine: 1, - EndColumn: 8, - Snippet: "snippetB", - }, - { - File: "file", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "snippet", - }, - }, - }, - }, - { - SeverityDetails: formats.SeverityDetails{ - Severity: "Medium", - SeverityNumValue: 14, - }, - Finding: "sast finding", - Location: formats.Location{ - File: "file2", - StartLine: 5, - StartColumn: 6, - EndLine: 7, - EndColumn: 8, - Snippet: "other-snippet", - }, - }, - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.ElementsMatch(t, tc.expectedOutput, prepareSast(tc.input, false)) - }) - } -} - -func TestGetFinalApplicabilityStatus(t *testing.T) { - testCases := []struct { - name string - input []jasutils.ApplicabilityStatus - expectedOutput jasutils.ApplicabilityStatus - }{ - { - name: "applicable wins all statuses", - input: []jasutils.ApplicabilityStatus{jasutils.ApplicabilityUndetermined, jasutils.Applicable, jasutils.NotCovered, jasutils.NotApplicable}, - expectedOutput: jasutils.Applicable, - }, - { - name: "undetermined wins not covered", - input: []jasutils.ApplicabilityStatus{jasutils.NotCovered, jasutils.ApplicabilityUndetermined, jasutils.NotCovered, jasutils.NotApplicable}, - expectedOutput: jasutils.ApplicabilityUndetermined, - }, - { - name: "not covered wins not applicable", - input: []jasutils.ApplicabilityStatus{jasutils.NotApplicable, jasutils.NotCovered, jasutils.NotApplicable}, - expectedOutput: jasutils.NotCovered, - }, - { - name: "all statuses are not applicable", - input: []jasutils.ApplicabilityStatus{jasutils.NotApplicable, jasutils.NotApplicable, jasutils.NotApplicable}, - expectedOutput: jasutils.NotApplicable, - }, - { - name: "no statuses", - input: []jasutils.ApplicabilityStatus{}, - expectedOutput: jasutils.NotScanned, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, tc.expectedOutput, getFinalApplicabilityStatus(tc.input)) - }) - } -} diff --git a/utils/resultwriter.go b/utils/resultwriter.go deleted file mode 100644 index 3bb8ebbf..00000000 --- a/utils/resultwriter.go +++ /dev/null @@ -1,589 +0,0 @@ -package utils - -import ( - "bytes" - "encoding/json" - "fmt" - "strconv" - "strings" - - "github.com/jfrog/jfrog-cli-core/v2/common/format" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-security/utils/formats" - "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" - "github.com/jfrog/jfrog-cli-security/utils/jasutils" - "github.com/jfrog/jfrog-cli-security/utils/results" - "github.com/jfrog/jfrog-cli-security/utils/severityutils" - "github.com/jfrog/jfrog-cli-security/utils/techutils" - clientUtils "github.com/jfrog/jfrog-client-go/utils" - "github.com/jfrog/jfrog-client-go/utils/errorutils" - "github.com/jfrog/jfrog-client-go/utils/io/fileutils" - "github.com/jfrog/jfrog-client-go/utils/log" - "github.com/jfrog/jfrog-client-go/xray/services" - "github.com/owenrumney/go-sarif/v2/sarif" - "golang.org/x/exp/slices" -) - -const MissingCveScore = "0" -const maxPossibleCve = 10.0 - -type ResultsWriter struct { - // The scan cmdResults. - cmdResults *results.SecurityCommandResults - // SimpleJsonError Errors to be added to output of the SimpleJson format. - simpleJsonError []formats.SimpleJsonError - // Format The output format. - format format.OutputFormat - // IncludeVulnerabilities If true, include all vulnerabilities as part of the output. Else, include violations only. - includeVulnerabilities bool - // IncludeLicenses If true, also include license violations as part of the output. - includeLicenses bool - // IsMultipleRoots multipleRoots is set to true, in case the given results array contains (or may contain) results of several projects (like in binary scan). - isMultipleRoots bool - // PrintExtended, If true, show extended results. - printExtended bool - // The scanType (binary,dependency) - scanType services.ScanType - // For table format - show table only for the given subScansPreformed - subScansPreformed []SubScanType - // Messages - Option array of messages, to be displayed if the format is Table - messages []string -} - -func NewResultsWriter(scanResults *results.SecurityCommandResults) *ResultsWriter { - return &ResultsWriter{cmdResults: scanResults} -} - -func (rw *ResultsWriter) SetOutputFormat(f format.OutputFormat) *ResultsWriter { - rw.format = f - return rw -} - -func (rw *ResultsWriter) SetScanType(scanType services.ScanType) *ResultsWriter { - rw.scanType = scanType - return rw -} - -func (rw *ResultsWriter) SetSimpleJsonError(jsonErrors []formats.SimpleJsonError) *ResultsWriter { - rw.simpleJsonError = jsonErrors - return rw -} - -func (rw *ResultsWriter) SetIncludeVulnerabilities(includeVulnerabilities bool) *ResultsWriter { - rw.includeVulnerabilities = includeVulnerabilities - return rw -} - -func (rw *ResultsWriter) SetIncludeLicenses(licenses bool) *ResultsWriter { - rw.includeLicenses = licenses - return rw -} - -func (rw *ResultsWriter) SetIsMultipleRootProject(isMultipleRootProject bool) *ResultsWriter { - rw.isMultipleRoots = isMultipleRootProject - return rw -} - -func (rw *ResultsWriter) SetPrintExtendedTable(extendedTable bool) *ResultsWriter { - rw.printExtended = extendedTable - return rw -} - -func (rw *ResultsWriter) SetExtraMessages(messages []string) *ResultsWriter { - rw.messages = messages - return rw -} - -func (rw *ResultsWriter) SetSubScansPreformed(subScansPreformed []SubScanType) *ResultsWriter { - rw.subScansPreformed = subScansPreformed - return rw -} - -// PrintScanResults prints the scan results in the specified format. -// Note that errors are printed only with SimpleJson format. -func (rw *ResultsWriter) PrintScanResults() error { - switch rw.format { - case format.Table: - return rw.printScanResultsTables() - case format.SimpleJson: - jsonTable, err := rw.convertScanToSimpleJson() - if err != nil { - return err - } - return PrintJson(jsonTable) - case format.Json: - return PrintJson(rw.cmdResults.GetScaScansXrayResults()) - case format.Sarif: - return PrintSarif(rw.cmdResults, rw.isMultipleRoots, rw.includeLicenses) - } - return nil -} -func (rw *ResultsWriter) printScanResultsTables() (err error) { - printMessages(rw.messages) - violations, vulnerabilities, licenses := SplitScanResults(rw.cmdResults.ScaResults) - if rw.cmdResults.IsIssuesFound() { - var resultsPath string - if resultsPath, err = writeJsonResults(rw.cmdResults); err != nil { - return - } - printMessage(coreutils.PrintTitle("The full scan results are available here: ") + coreutils.PrintLink(resultsPath)) - } - log.Output() - if shouldPrintTable(rw.subScansPreformed, ScaScan, rw.scanType) { - if rw.includeVulnerabilities { - err = PrintVulnerabilitiesTable(vulnerabilities, rw.cmdResults, rw.isMultipleRoots, rw.printExtended, rw.scanType) - } else { - err = PrintViolationsTable(violations, rw.cmdResults, rw.isMultipleRoots, rw.printExtended, rw.scanType) - } - if err != nil { - return - } - if rw.includeLicenses { - if err = PrintLicensesTable(licenses, rw.printExtended, rw.scanType); err != nil { - return - } - } - } - if shouldPrintTable(rw.subScansPreformed, SecretsScan, rw.scanType) { - if err = PrintSecretsTable(rw.cmdResults.ExtendedScanResults.SecretsScanResults, rw.cmdResults.ExtendedScanResults.EntitledForJas); err != nil { - return - } - } - if shouldPrintTable(rw.subScansPreformed, IacScan, rw.scanType) { - if err = PrintIacTable(rw.cmdResults.ExtendedScanResults.IacScanResults, rw.cmdResults.ExtendedScanResults.EntitledForJas); err != nil { - return - } - } - if !shouldPrintTable(rw.subScansPreformed, SastScan, rw.scanType) { - return nil - } - return PrintSastTable(rw.cmdResults.ExtendedScanResults.SastScanResults, rw.cmdResults.ExtendedScanResults.EntitledForJas) -} - -func shouldPrintTable(requestedScans []SubScanType, subScan SubScanType, scanType services.ScanType) bool { - if scanType == services.Binary && (subScan == IacScan || subScan == SastScan) { - return false - } - return len(requestedScans) == 0 || slices.Contains(requestedScans, subScan) -} - -func printMessages(messages []string) { - if len(messages) > 0 { - log.Output() - } - for _, m := range messages { - printMessage(m) - } -} - -func printMessage(message string) { - log.Output("💬" + message) -} - -func GenereateSarifReportFromResults(cmdResults *results.SecurityCommandResults, isMultipleRoots, includeLicenses bool, allowedLicenses []string) (report *sarif.Report, err error) { - report, err = sarifutils.NewReport() - if err != nil { - return - } - xrayRun, err := convertXrayResponsesToSarifRun(cmdResults, isMultipleRoots, includeLicenses, allowedLicenses) - if err != nil { - return - } - - report.Runs = append(report.Runs, xrayRun) - report.Runs = append(report.Runs, cmdResults.ExtendedScanResults.ApplicabilityScanResults...) - report.Runs = append(report.Runs, cmdResults.ExtendedScanResults.IacScanResults...) - report.Runs = append(report.Runs, cmdResults.ExtendedScanResults.SecretsScanResults...) - report.Runs = append(report.Runs, cmdResults.ExtendedScanResults.SastScanResults...) - - return -} - -func convertXrayResponsesToSarifRun(cmdResults *results.SecurityCommandResults, isMultipleRoots, includeLicenses bool, allowedLicenses []string) (run *sarif.Run, err error) { - xrayJson, err := ConvertXrayScanToSimpleJson(cmdResults, isMultipleRoots, includeLicenses, true, allowedLicenses) - if err != nil { - return - } - xrayRun := sarif.NewRunWithInformationURI("JFrog Xray SCA", BaseDocumentationURL+"sca") - xrayRun.Tool.Driver.Version = &cmdResults.XrayVersion - if len(xrayJson.Vulnerabilities) > 0 || len(xrayJson.SecurityViolations) > 0 || len(xrayJson.LicensesViolations) > 0 { - if err = extractXrayIssuesToSarifRun(xrayRun, xrayJson); err != nil { - return - } - } - run = xrayRun - return -} - -func extractXrayIssuesToSarifRun(run *sarif.Run, xrayJson formats.SimpleJsonResults) error { - for _, vulnerability := range xrayJson.Vulnerabilities { - if err := addXrayCveIssueToSarifRun(vulnerability, run); err != nil { - return err - } - } - for _, violation := range xrayJson.SecurityViolations { - if err := addXrayCveIssueToSarifRun(violation, run); err != nil { - return err - } - } - for _, license := range xrayJson.LicensesViolations { - if err := addXrayLicenseViolationToSarifRun(license, run); err != nil { - return err - } - } - return nil -} - -func addXrayCveIssueToSarifRun(issue formats.VulnerabilityOrViolationRow, run *sarif.Run) (err error) { - maxCveScore, err := findMaxCVEScore(issue.Cves) - if err != nil { - return - } - location, err := getXrayIssueLocationIfValidExists(issue.Technology, run) - if err != nil { - return - } - formattedDirectDependencies, err := getDirectDependenciesFormatted(issue.Components) - if err != nil { - return - } - cveId := GetIssueIdentifier(issue.Cves, issue.IssueId) - markdownDescription := getSarifTableDescription(formattedDirectDependencies, maxCveScore, issue.Applicable, issue.FixedVersions) - addXrayIssueToSarifRun( - cveId, - issue.ImpactedDependencyName, - issue.ImpactedDependencyVersion, - severityutils.GetSeverity(issue.Severity), - maxCveScore, - issue.Summary, - getXrayIssueSarifHeadline(issue.ImpactedDependencyName, issue.ImpactedDependencyVersion, cveId), - markdownDescription, - issue.Components, - location, - run, - ) - return -} - -func addXrayLicenseViolationToSarifRun(license formats.LicenseRow, run *sarif.Run) (err error) { - formattedDirectDependencies, err := getDirectDependenciesFormatted(license.Components) - if err != nil { - return - } - addXrayIssueToSarifRun( - license.LicenseKey, - license.ImpactedDependencyName, - license.ImpactedDependencyVersion, - severityutils.GetSeverity(license.Severity), - MissingCveScore, - getLicenseViolationSummary(license.ImpactedDependencyName, license.ImpactedDependencyVersion, license.LicenseKey), - getXrayLicenseSarifHeadline(license.ImpactedDependencyName, license.ImpactedDependencyVersion, license.LicenseKey), - getLicenseViolationMarkdown(license.ImpactedDependencyName, license.ImpactedDependencyVersion, license.LicenseKey, formattedDirectDependencies), - license.Components, - getXrayIssueLocation(""), - run, - ) - return -} - -func addXrayIssueToSarifRun(issueId, impactedDependencyName, impactedDependencyVersion string, severity severityutils.Severity, severityScore, summary, title, markdownDescription string, components []formats.ComponentRow, location *sarif.Location, run *sarif.Run) { - // Add rule if not exists - ruleId := getXrayIssueSarifRuleId(impactedDependencyName, impactedDependencyVersion, issueId) - if rule, _ := run.GetRuleById(ruleId); rule == nil { - addXrayRule(ruleId, title, severityScore, summary, markdownDescription, run) - } - // Add result for each component - - for _, directDependency := range components { - msg := getXrayIssueSarifHeadline(directDependency.Name, directDependency.Version, issueId) - if result := run.CreateResultForRule(ruleId).WithMessage(sarif.NewTextMessage(msg)).WithLevel(severityutils.SeverityToSarifSeverityLevel(severity).String()); location != nil { - result.AddLocation(location) - } - } - -} - -func getDescriptorFullPath(tech techutils.Technology, run *sarif.Run) (string, error) { - descriptors := tech.GetPackageDescriptor() - if len(descriptors) == 1 { - // Generate the full path - return sarifutils.GetFullLocationFileName(strings.TrimSpace(descriptors[0]), run.Invocations), nil - } - for _, descriptor := range descriptors { - // If multiple options return first to match - absolutePath := sarifutils.GetFullLocationFileName(strings.TrimSpace(descriptor), run.Invocations) - if exists, err := fileutils.IsFileExists(absolutePath, false); err != nil { - return "", err - } else if exists { - return absolutePath, nil - } - } - return "", nil -} - -// Get the descriptor location with the Xray issues if exists. -func getXrayIssueLocationIfValidExists(tech techutils.Technology, run *sarif.Run) (location *sarif.Location, err error) { - descriptorPath, err := getDescriptorFullPath(tech, run) - if err != nil { - return - } - return getXrayIssueLocation(descriptorPath), nil -} - -func getXrayIssueLocation(filePath string) *sarif.Location { - if strings.TrimSpace(filePath) == "" { - filePath = "Package-Descriptor" - } - return sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://" + filePath))) -} - -func addXrayRule(ruleId, ruleDescription, maxCveScore, summary, markdownDescription string, run *sarif.Run) { - rule := run.AddRule(ruleId) - - if maxCveScore != MissingCveScore { - cveRuleProperties := sarif.NewPropertyBag() - cveRuleProperties.Add(severityutils.SarifSeverityRuleProperty, maxCveScore) - rule.WithProperties(cveRuleProperties.Properties) - } - - rule.WithDescription(ruleDescription) - rule.WithHelp(&sarif.MultiformatMessageString{ - Text: &summary, - Markdown: &markdownDescription, - }) -} - -func ConvertXrayScanToSimpleJson(cmdResults *results.SecurityCommandResults, isMultipleRoots, includeLicenses, simplifiedOutput bool, allowedLicenses []string) (formats.SimpleJsonResults, error) { - violations, vulnerabilities, licenses := SplitScanResults(cmdResults.ScaResults) - jsonTable := formats.SimpleJsonResults{} - if len(vulnerabilities) > 0 { - vulJsonTable, err := PrepareVulnerabilities(vulnerabilities, cmdResults, isMultipleRoots, simplifiedOutput) - if err != nil { - return formats.SimpleJsonResults{}, err - } - jsonTable.Vulnerabilities = vulJsonTable - } - if includeLicenses || len(allowedLicenses) > 0 { - licJsonTable, err := PrepareLicenses(licenses) - if err != nil { - return formats.SimpleJsonResults{}, err - } - if includeLicenses { - jsonTable.Licenses = licJsonTable - } - jsonTable.LicensesViolations = GetViolatedLicenses(allowedLicenses, licJsonTable) - } - if len(violations) > 0 { - secViolationsJsonTable, licViolationsJsonTable, opRiskViolationsJsonTable, err := PrepareViolations(violations, cmdResults, isMultipleRoots, simplifiedOutput) - if err != nil { - return formats.SimpleJsonResults{}, err - } - jsonTable.SecurityViolations = secViolationsJsonTable - jsonTable.LicensesViolations = licViolationsJsonTable - jsonTable.OperationalRiskViolations = opRiskViolationsJsonTable - } - jsonTable.MultiScanId = cmdResults.MultiScanId - return jsonTable, nil -} - -func GetViolatedLicenses(allowedLicenses []string, licenses []formats.LicenseRow) (violatedLicenses []formats.LicenseRow) { - if len(allowedLicenses) == 0 { - return - } - for _, license := range licenses { - if !slices.Contains(allowedLicenses, license.LicenseKey) { - violatedLicenses = append(violatedLicenses, license) - } - } - return -} - -func (rw *ResultsWriter) convertScanToSimpleJson() (formats.SimpleJsonResults, error) { - jsonTable, err := ConvertXrayScanToSimpleJson(rw.cmdResults, rw.isMultipleRoots, rw.includeLicenses, false, nil) - if err != nil { - return formats.SimpleJsonResults{}, err - } - if len(rw.cmdResults.ExtendedScanResults.SecretsScanResults) > 0 { - jsonTable.Secrets = PrepareSecrets(rw.cmdResults.ExtendedScanResults.SecretsScanResults) - } - if len(rw.cmdResults.ExtendedScanResults.IacScanResults) > 0 { - jsonTable.Iacs = PrepareIacs(rw.cmdResults.ExtendedScanResults.IacScanResults) - } - if len(rw.cmdResults.ExtendedScanResults.SastScanResults) > 0 { - jsonTable.Sast = PrepareSast(rw.cmdResults.ExtendedScanResults.SastScanResults) - } - jsonTable.Errors = rw.simpleJsonError - - return jsonTable, nil -} - -func GetIssueIdentifier(cvesRow []formats.CveRow, issueId string) string { - var identifier string - if len(cvesRow) != 0 { - var cvesBuilder strings.Builder - for _, cve := range cvesRow { - cvesBuilder.WriteString(cve.Id + ", ") - } - identifier = strings.TrimSuffix(cvesBuilder.String(), ", ") - } - if identifier == "" { - identifier = issueId - } - - return identifier -} - -func getXrayIssueSarifRuleId(depName, version, key string) string { - return fmt.Sprintf("%s_%s_%s", key, depName, version) -} - -func getXrayIssueSarifHeadline(depName, version, key string) string { - return fmt.Sprintf("[%s] %s %s", key, depName, version) -} - -func getXrayLicenseSarifHeadline(depName, version, key string) string { - return fmt.Sprintf("License violation [%s] %s %s", key, depName, version) -} - -func getLicenseViolationSummary(depName, version, key string) string { - return fmt.Sprintf("Dependency %s version %s is using a license (%s) that is not allowed.", depName, version, key) -} - -func getLicenseViolationMarkdown(depName, version, key, formattedDirectDependencies string) string { - return fmt.Sprintf("**The following direct dependencies are utilizing the `%s %s` dependency with `%s` license violation:**\n%s", depName, version, key, formattedDirectDependencies) -} - -func getDirectDependenciesFormatted(directDependencies []formats.ComponentRow) (string, error) { - var formattedDirectDependencies strings.Builder - for _, dependency := range directDependencies { - if _, err := formattedDirectDependencies.WriteString(fmt.Sprintf("`%s %s`
", dependency.Name, dependency.Version)); err != nil { - return "", err - } - } - return strings.TrimSuffix(formattedDirectDependencies.String(), "
"), nil -} - -func getSarifTableDescription(formattedDirectDependencies, maxCveScore, applicable string, fixedVersions []string) string { - descriptionFixVersions := "No fix available" - if len(fixedVersions) > 0 { - descriptionFixVersions = strings.Join(fixedVersions, ", ") - } - if applicable == jasutils.NotScanned.String() { - return fmt.Sprintf("| Severity Score | Direct Dependencies | Fixed Versions |\n| :---: | :----: | :---: |\n| %s | %s | %s |", - maxCveScore, formattedDirectDependencies, descriptionFixVersions) - } - return fmt.Sprintf("| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| %s | %s | %s | %s |", - maxCveScore, applicable, formattedDirectDependencies, descriptionFixVersions) -} - -func findMaxCVEScore(cves []formats.CveRow) (string, error) { - maxCve := 0.0 - for _, cve := range cves { - if cve.CvssV3 == "" { - continue - } - floatCve, err := strconv.ParseFloat(cve.CvssV3, 32) - if err != nil { - return "", err - } - if floatCve > maxCve { - maxCve = floatCve - } - // if found maximum possible cve score, no need to keep iterating - if maxCve == maxPossibleCve { - break - } - } - strCve := fmt.Sprintf("%.1f", maxCve) - - return strCve, nil -} - -// Splits scan responses into aggregated lists of violations, vulnerabilities and licenses. -func SplitScanResults(results []*results.ScaScanResult) ([]services.Violation, []services.Vulnerability, []services.License) { - var violations []services.Violation - var vulnerabilities []services.Vulnerability - var licenses []services.License - for _, scan := range results { - for _, result := range scan.XrayResults { - violations = append(violations, result.Violations...) - vulnerabilities = append(vulnerabilities, result.Vulnerabilities...) - licenses = append(licenses, result.Licenses...) - } - } - return violations, vulnerabilities, licenses -} - -func writeJsonResults(cmdResults *results.SecurityCommandResults) (resultsPath string, err error) { - out, err := fileutils.CreateTempFile() - if errorutils.CheckError(err) != nil { - return - } - defer func() { - e := out.Close() - if err == nil { - err = e - } - }() - bytesRes, err := json.Marshal(&cmdResults) - if errorutils.CheckError(err) != nil { - return - } - var content bytes.Buffer - err = json.Indent(&content, bytesRes, "", " ") - if errorutils.CheckError(err) != nil { - return - } - _, err = out.Write(content.Bytes()) - if errorutils.CheckError(err) != nil { - return - } - resultsPath = out.Name() - return -} - -func PrintJson(output interface{}) error { - results, err := json.Marshal(output) - if err != nil { - return errorutils.CheckError(err) - } - log.Output(clientUtils.IndentJson(results)) - return nil -} - -func PrintSarif(cmdResults *results.SecurityCommandResults, isMultipleRoots, includeLicenses bool) error { - sarifReport, err := GenereateSarifReportFromResults(cmdResults, isMultipleRoots, includeLicenses, nil) - if err != nil { - return err - } - sarifFile, err := sarifutils.ConvertSarifReportToString(sarifReport) - if err != nil { - return err - } - log.Output(sarifFile) - return nil -} - -func CheckIfFailBuild(results []services.ScanResponse) bool { - for _, result := range results { - for _, violation := range result.Violations { - if violation.FailBuild { - return true - } - } - } - return false -} - -func IsEmptyScanResponse(results []services.ScanResponse) bool { - for _, result := range results { - if len(result.Violations) > 0 || len(result.Vulnerabilities) > 0 || len(result.Licenses) > 0 { - return false - } - } - return true -} - -func NewFailBuildError() error { - return coreutils.CliError{ExitCode: coreutils.ExitCodeVulnerableBuild, ErrorMsg: "One or more of the violations found are set to fail builds that include them"} -} diff --git a/utils/resultwriter_test.go b/utils/resultwriter_test.go deleted file mode 100644 index 417ed1fe..00000000 --- a/utils/resultwriter_test.go +++ /dev/null @@ -1,406 +0,0 @@ -package utils - -import ( - "os" - "path/filepath" - "testing" - - "github.com/jfrog/jfrog-cli-core/v2/utils/tests" - "github.com/jfrog/jfrog-cli-security/utils/formats" - "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" - "github.com/jfrog/jfrog-cli-security/utils/jasutils" - "github.com/jfrog/jfrog-cli-security/utils/techutils" - "github.com/jfrog/jfrog-client-go/xray/services" - "github.com/owenrumney/go-sarif/v2/sarif" - "github.com/stretchr/testify/assert" -) - -func TestGetVulnerabilityOrViolationSarifHeadline(t *testing.T) { - assert.Equal(t, "[CVE-2022-1234] loadsh 1.4.1", getXrayIssueSarifHeadline("loadsh", "1.4.1", "CVE-2022-1234")) - assert.NotEqual(t, "[CVE-2022-1234] loadsh 1.4.1", getXrayIssueSarifHeadline("loadsh", "1.2.1", "CVE-2022-1234")) -} - -func TestGetIssueIdentifier(t *testing.T) { - issueId := "XRAY-123456" - cvesRow := []formats.CveRow{{Id: "CVE-2022-1234"}} - assert.Equal(t, "CVE-2022-1234", GetIssueIdentifier(cvesRow, issueId)) - cvesRow = append(cvesRow, formats.CveRow{Id: "CVE-2019-1234"}) - assert.Equal(t, "CVE-2022-1234, CVE-2019-1234", GetIssueIdentifier(cvesRow, issueId)) - assert.Equal(t, issueId, GetIssueIdentifier(nil, issueId)) -} - -func TestGetDirectDependenciesFormatted(t *testing.T) { - testCases := []struct { - name string - directDeps []formats.ComponentRow - expectedOutput string - }{ - { - name: "Single direct dependency", - directDeps: []formats.ComponentRow{ - {Name: "example-package", Version: "1.0.0"}, - }, - expectedOutput: "`example-package 1.0.0`", - }, - { - name: "Multiple direct dependencies", - directDeps: []formats.ComponentRow{ - {Name: "dependency1", Version: "1.0.0"}, - {Name: "dependency2", Version: "2.0.0"}, - }, - expectedOutput: "`dependency1 1.0.0`
`dependency2 2.0.0`", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - output, err := getDirectDependenciesFormatted(tc.directDeps) - assert.NoError(t, err) - assert.Equal(t, tc.expectedOutput, output) - }) - } -} - -func TestGetSarifTableDescription(t *testing.T) { - testCases := []struct { - name string - formattedDeps string - maxCveScore string - status jasutils.ApplicabilityStatus - fixedVersions []string - expectedDescription string - }{ - { - name: "Applicable vulnerability", - formattedDeps: "`example-package 1.0.0`", - maxCveScore: "7.5", - status: "Applicable", - fixedVersions: []string{"1.0.1", "1.0.2"}, - expectedDescription: "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.5 | Applicable | `example-package 1.0.0` | 1.0.1, 1.0.2 |", - }, - { - name: "Not-scanned vulnerability", - formattedDeps: "`example-package 2.0.0`", - maxCveScore: "6.2", - status: "", - fixedVersions: []string{"2.0.1"}, - expectedDescription: "| Severity Score | Direct Dependencies | Fixed Versions |\n| :---: | :----: | :---: |\n| 6.2 | `example-package 2.0.0` | 2.0.1 |", - }, - { - name: "No fixed versions", - formattedDeps: "`example-package 3.0.0`", - maxCveScore: "3.0", - status: "", - fixedVersions: []string{}, - expectedDescription: "| Severity Score | Direct Dependencies | Fixed Versions |\n| :---: | :----: | :---: |\n| 3.0 | `example-package 3.0.0` | No fix available |", - }, - { - name: "Not-covered vulnerability", - formattedDeps: "`example-package 3.0.0`", - maxCveScore: "3.0", - status: "Not covered", - fixedVersions: []string{"3.0.1"}, - expectedDescription: "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.0 | Not covered | `example-package 3.0.0` | 3.0.1 |", - }, - { - name: "Undetermined vulnerability", - formattedDeps: "`example-package 3.0.0`", - maxCveScore: "3.0", - status: "Undetermined", - fixedVersions: []string{"3.0.1"}, - expectedDescription: "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.0 | Undetermined | `example-package 3.0.0` | 3.0.1 |", - }, - { - name: "Not-status vulnerability", - formattedDeps: "`example-package 3.0.0`", - maxCveScore: "3.0", - status: "Not status", - fixedVersions: []string{"3.0.1"}, - expectedDescription: "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.0 | Not status | `example-package 3.0.0` | 3.0.1 |", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - output := getSarifTableDescription(tc.formattedDeps, tc.maxCveScore, tc.status.String(), tc.fixedVersions) - assert.Equal(t, tc.expectedDescription, output) - }) - } -} - -func TestFindMaxCVEScore(t *testing.T) { - testCases := []struct { - name string - cves []formats.CveRow - expectedOutput string - expectedError bool - }{ - { - name: "CVEScore with valid float values", - cves: []formats.CveRow{ - {Id: "CVE-2021-1234", CvssV3: "7.5"}, - {Id: "CVE-2021-5678", CvssV3: "9.2"}, - }, - expectedOutput: "9.2", - }, - { - name: "CVEScore with invalid float value", - cves: []formats.CveRow{ - {Id: "CVE-2022-4321", CvssV3: "invalid"}, - }, - expectedOutput: "", - expectedError: true, - }, - { - name: "CVEScore without values", - cves: []formats.CveRow{}, - expectedOutput: "0.0", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - output, err := findMaxCVEScore(tc.cves) - assert.False(t, tc.expectedError && err == nil) - assert.Equal(t, tc.expectedOutput, output) - }) - } -} - -func TestGetXrayIssueLocationIfValidExists(t *testing.T) { - testDir, cleanup := tests.CreateTempDirWithCallbackAndAssert(t) - defer cleanup() - invocation := sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(testDir)) - file, err := os.Create(filepath.Join(testDir, "go.mod")) - assert.NoError(t, err) - assert.NotNil(t, file) - defer func() { assert.NoError(t, file.Close()) }() - file2, err := os.Create(filepath.Join(testDir, "build.gradle.kts")) - assert.NoError(t, err) - assert.NotNil(t, file2) - defer func() { assert.NoError(t, file2.Close()) }() - - testCases := []struct { - name string - tech techutils.Technology - run *sarif.Run - expectedOutput *sarif.Location - }{ - { - name: "No descriptor information", - tech: techutils.Pip, - run: sarifutils.CreateRunWithDummyResults().WithInvocations([]*sarif.Invocation{invocation}), - expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://Package-Descriptor"))), - }, - { - name: "One descriptor information", - tech: techutils.Go, - run: sarifutils.CreateRunWithDummyResults().WithInvocations([]*sarif.Invocation{invocation}), - expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://" + filepath.Join(testDir, "go.mod")))), - }, - { - name: "One descriptor information - no invocation", - tech: techutils.Go, - run: sarifutils.CreateRunWithDummyResults(), - expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://go.mod"))), - }, - { - name: "Multiple descriptor information", - tech: techutils.Gradle, - run: sarifutils.CreateRunWithDummyResults().WithInvocations([]*sarif.Invocation{invocation}), - expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://" + filepath.Join(testDir, "build.gradle.kts")))), - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - output, err := getXrayIssueLocationIfValidExists(tc.tech, tc.run) - if assert.NoError(t, err) { - assert.Equal(t, tc.expectedOutput, output) - } - }) - } -} - -func TestConvertXrayScanToSimpleJson(t *testing.T) { - vulnerabilities := []services.Vulnerability{ - { - IssueId: "XRAY-1", - Summary: "summary-1", - Severity: "high", - Components: map[string]services.Component{"component-A": {}, "component-B": {}}, - }, - { - IssueId: "XRAY-2", - Summary: "summary-2", - Severity: "low", - Components: map[string]services.Component{"component-B": {}}, - }, - } - expectedVulnerabilities := []formats.VulnerabilityOrViolationRow{ - { - Summary: "summary-1", - IssueId: "XRAY-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High"}, - ImpactedDependencyName: "component-A", - }, - }, - { - Summary: "summary-1", - IssueId: "XRAY-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High"}, - ImpactedDependencyName: "component-B", - }, - }, - { - Summary: "summary-2", - IssueId: "XRAY-2", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low"}, - ImpactedDependencyName: "component-B", - }, - }, - } - - violations := []services.Violation{ - { - IssueId: "XRAY-1", - Summary: "summary-1", - Severity: "high", - WatchName: "watch-1", - ViolationType: "security", - Components: map[string]services.Component{"component-A": {}, "component-B": {}}, - }, - { - IssueId: "XRAY-2", - Summary: "summary-2", - Severity: "low", - WatchName: "watch-1", - ViolationType: "license", - LicenseKey: "license-1", - Components: map[string]services.Component{"component-B": {}}, - }, - } - expectedSecViolations := []formats.VulnerabilityOrViolationRow{ - { - Summary: "summary-1", - IssueId: "XRAY-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High"}, - ImpactedDependencyName: "component-A", - }, - }, - { - Summary: "summary-1", - IssueId: "XRAY-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High"}, - ImpactedDependencyName: "component-B", - }, - }, - } - expectedLicViolations := []formats.LicenseRow{ - { - LicenseKey: "license-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low"}, - ImpactedDependencyName: "component-B", - }, - }, - } - - licenses := []services.License{ - { - Key: "license-1", - Name: "license-1-name", - Components: map[string]services.Component{"component-A": {}, "component-B": {}}, - }, - { - Key: "license-2", - Name: "license-2-name", - Components: map[string]services.Component{"component-B": {}}, - }, - } - expectedLicenses := []formats.LicenseRow{ - { - LicenseKey: "license-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "component-A"}, - }, - { - LicenseKey: "license-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "component-B"}, - }, - { - LicenseKey: "license-2", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "component-B"}, - }, - } - - testCases := []struct { - name string - result services.ScanResponse - includeLicenses bool - allowedLicenses []string - expectedOutput formats.SimpleJsonResults - }{ - { - name: "Vulnerabilities only", - includeLicenses: false, - allowedLicenses: nil, - result: services.ScanResponse{Vulnerabilities: vulnerabilities, Licenses: licenses}, - expectedOutput: formats.SimpleJsonResults{Vulnerabilities: expectedVulnerabilities}, - }, - { - name: "Vulnerabilities with licenses", - includeLicenses: true, - allowedLicenses: nil, - result: services.ScanResponse{Vulnerabilities: vulnerabilities, Licenses: licenses}, - expectedOutput: formats.SimpleJsonResults{Vulnerabilities: expectedVulnerabilities, Licenses: expectedLicenses}, - }, - { - name: "Vulnerabilities only - with allowed licenses", - includeLicenses: false, - allowedLicenses: []string{"license-1"}, - result: services.ScanResponse{Vulnerabilities: vulnerabilities, Licenses: licenses}, - expectedOutput: formats.SimpleJsonResults{ - Vulnerabilities: expectedVulnerabilities, - LicensesViolations: []formats.LicenseRow{ - { - LicenseKey: "license-2", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "component-B"}, - }, - }, - }, - }, - { - name: "Violations only", - includeLicenses: false, - allowedLicenses: nil, - result: services.ScanResponse{Violations: violations, Licenses: licenses}, - expectedOutput: formats.SimpleJsonResults{SecurityViolations: expectedSecViolations, LicensesViolations: expectedLicViolations}, - }, - { - name: "Violations - override allowed licenses", - includeLicenses: false, - allowedLicenses: []string{"license-1"}, - result: services.ScanResponse{Violations: violations, Licenses: licenses}, - expectedOutput: formats.SimpleJsonResults{SecurityViolations: expectedSecViolations, LicensesViolations: expectedLicViolations}, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - results := NewAuditResults() - scaScanResult := ScaScanResult{XrayResults: []services.ScanResponse{tc.result}} - results.ScaResults = append(results.ScaResults, &scaScanResult) - output, err := ConvertXrayScanToSimpleJson(results, false, tc.includeLicenses, true, tc.allowedLicenses) - if assert.NoError(t, err) { - assert.ElementsMatch(t, tc.expectedOutput.Vulnerabilities, output.Vulnerabilities) - assert.ElementsMatch(t, tc.expectedOutput.SecurityViolations, output.SecurityViolations) - assert.ElementsMatch(t, tc.expectedOutput.LicensesViolations, output.LicensesViolations) - assert.ElementsMatch(t, tc.expectedOutput.Licenses, output.Licenses) - assert.ElementsMatch(t, tc.expectedOutput.OperationalRiskViolations, output.OperationalRiskViolations) - } - }) - } -} diff --git a/utils/techutils/techutils.go b/utils/techutils/techutils.go index 0b89dd72..97703f99 100644 --- a/utils/techutils/techutils.go +++ b/utils/techutils/techutils.go @@ -67,6 +67,8 @@ var packageTypes = map[string]string{ type TechData struct { // The name of the package type used in this technology. packageType string + // The package type ID used in Xray. + packageTypeId string // Suffixes of file/directory names that indicate if a project uses this technology. // The name of at least one of the files/directories in the project's directory must end with one of these suffixes. indicators []string @@ -84,7 +86,7 @@ type TechData struct { // The operator for package versioning packageVersionOperator string // The package installation command of a package - packageInstallationCommand string + packageInstallationCommand string } // Given a file content, returns true if the content is an indicator of the technology. @@ -113,6 +115,7 @@ var technologiesData = map[Technology]TechData{ exclude: []string{".yarnrc.yml", "yarn.lock", ".yarn"}, packageDescriptors: []string{"package.json"}, packageVersionOperator: "@", + packageTypeId: "npm://", packageInstallationCommand: "update", }, Yarn: { @@ -235,6 +238,13 @@ func (tech Technology) GetPackageType() string { return technologiesData[tech].packageType } +func (tech Technology) GetPackageTypeId() string { + if technologiesData[tech].packageTypeId == "" { + return fmt.Sprintf("%s://", tech.GetPackageType()) + } + return technologiesData[tech].packageTypeId +} + func (tech Technology) GetPackageDescriptor() []string { return technologiesData[tech].packageDescriptors } diff --git a/utils/xsc/analyticsmetrics_test.go b/utils/xsc/analyticsmetrics_test.go index e9b3fb12..0224a199 100644 --- a/utils/xsc/analyticsmetrics_test.go +++ b/utils/xsc/analyticsmetrics_test.go @@ -86,7 +86,7 @@ func TestAnalyticsMetricsService_createAuditResultsFromXscAnalyticsBasicGeneralE {name: "No audit results", auditResults: &results.SecurityCommandResults{}, want: xscservices.XscAnalyticsBasicGeneralEvent{EventStatus: xscservices.Completed}}, {name: "Valid audit result", auditResults: getDummyContentForGeneralEvent(true, false), want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 7, EventStatus: xscservices.Completed}}, {name: "Scan failed with findings.", auditResults: getDummyContentForGeneralEvent(false, true), want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 1, EventStatus: xscservices.Failed}}, - {name: "Scan failed no findings.", auditResults: &results.SecurityCommandResults{Targets: []*results.TargetResults{{Error: errors.New("an error")}}}, want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 0, EventStatus: xscservices.Failed}}, + {name: "Scan failed no findings.", auditResults: &results.SecurityCommandResults{Targets: []*results.TargetResults{{Errors: []error{errors.New("an error")}}}}, want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 0, EventStatus: xscservices.Failed}}, } mockServer, serverDetails := utils.XscServer(t, xscservices.AnalyticsMetricsMinXscVersion) defer mockServer.Close() @@ -129,7 +129,7 @@ func getDummyContentForGeneralEvent(withJas, withErr bool) *results.SecurityComm } if withErr { - scanResults.Error = errors.New("an error") + scanResults.Errors = []error{errors.New("an error")} } return cmdResults From da0bfb96cddab2409298c255c2692c65ebfb0875 Mon Sep 17 00:00:00 2001 From: attiasas Date: Wed, 3 Jul 2024 09:14:29 +0300 Subject: [PATCH 10/82] format --- utils/results/conversion/convertor.go | 2 +- .../conversion/sarifparser/sarifparser_test.go | 2 +- utils/results/results.go | 6 +++--- utils/results/results_test.go | 12 ++++++------ utils/techutils/techutils.go | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/utils/results/conversion/convertor.go b/utils/results/conversion/convertor.go index ffe6d496..4e12e2fb 100644 --- a/utils/results/conversion/convertor.go +++ b/utils/results/conversion/convertor.go @@ -21,7 +21,7 @@ type CommandResultsConvertor struct { } type ResultConvertParams struct { - // Control and override converting command results as multi target results + // Control and override converting command results as multi target results IsMultipleRoots *bool // Control if the output should include licenses information IncludeLicenses bool diff --git a/utils/results/conversion/sarifparser/sarifparser_test.go b/utils/results/conversion/sarifparser/sarifparser_test.go index 25781604..542a7286 100644 --- a/utils/results/conversion/sarifparser/sarifparser_test.go +++ b/utils/results/conversion/sarifparser/sarifparser_test.go @@ -52,7 +52,7 @@ func TestGetVulnerabilityOrViolationSarifHeadline(t *testing.T) { assert.NotEqual(t, "[CVE-2022-1234] comp 1.4.1", getScaIssueSarifHeadline("comp", "1.2.1", "CVE-2022-1234")) } -func TestgetXrayLicenseSarifHeadline(t *testing.T) { +func TestGetXrayLicenseSarifHeadline(t *testing.T) { assert.Equal(t, "License violation [MIT] in loadsh 1.4.1", getXrayLicenseSarifHeadline("loadsh", "1.4.1", "MIT")) assert.NotEqual(t, "License violation [] in comp 1.2.1", getXrayLicenseSarifHeadline("comp", "1.2.1", "MIT")) } diff --git a/utils/results/results.go b/utils/results/results.go index f3cfb2e7..00eeccd2 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -20,7 +20,7 @@ type SecurityCommandResults struct { // MultiScanId is a unique identifier that is used to group multiple scans together. MultiScanId string `json:"multi_scan_id,omitempty"` // Results for each target in the command - Targets []*TargetResults `json:"targets"` + Targets []*TargetResults `json:"targets"` targetsMutex sync.Mutex `json:"-"` // Error that occurred during the command execution Error error `json:"error,omitempty"` @@ -41,7 +41,7 @@ type TargetResults struct { ScaResults *ScaScanResults `json:"sca_scans,omitempty"` JasResults *JasScansResults `json:"jas_scans,omitempty"` // Errors that occurred during the scans - Errors []error `json:"errors,omitempty"` + Errors []error `json:"errors,omitempty"` errorsMutex sync.Mutex `json:"-"` } @@ -312,4 +312,4 @@ func (jsr *JasScansResults) HasInformationByType(scanType jasutils.JasScanType) } } return false -} \ No newline at end of file +} diff --git a/utils/results/results_test.go b/utils/results/results_test.go index 1e55d391..f82d58f4 100644 --- a/utils/results/results_test.go +++ b/utils/results/results_test.go @@ -1,13 +1,13 @@ package results import ( - // "testing" +// "testing" - // "github.com/jfrog/jfrog-cli-security/utils/formats" - // "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" - // "github.com/jfrog/jfrog-client-go/xray/services" - // "github.com/owenrumney/go-sarif/v2/sarif" - // "github.com/stretchr/testify/assert" +// "github.com/jfrog/jfrog-cli-security/utils/formats" +// "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" +// "github.com/jfrog/jfrog-client-go/xray/services" +// "github.com/owenrumney/go-sarif/v2/sarif" +// "github.com/stretchr/testify/assert" ) // func TestGetScaScanResultByTarget(t *testing.T) { diff --git a/utils/techutils/techutils.go b/utils/techutils/techutils.go index 97703f99..d68454ee 100644 --- a/utils/techutils/techutils.go +++ b/utils/techutils/techutils.go @@ -86,7 +86,7 @@ type TechData struct { // The operator for package versioning packageVersionOperator string // The package installation command of a package - packageInstallationCommand string + packageInstallationCommand string } // Given a file content, returns true if the content is an indicator of the technology. @@ -115,7 +115,7 @@ var technologiesData = map[Technology]TechData{ exclude: []string{".yarnrc.yml", "yarn.lock", ".yarn"}, packageDescriptors: []string{"package.json"}, packageVersionOperator: "@", - packageTypeId: "npm://", + packageTypeId: "npm://", packageInstallationCommand: "update", }, Yarn: { From 218797a240f3d39e1d4d09607a14e10a175af07d Mon Sep 17 00:00:00 2001 From: attiasas Date: Wed, 10 Jul 2024 12:08:23 +0300 Subject: [PATCH 11/82] format --- commands/scan/scan.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/commands/scan/scan.go b/commands/scan/scan.go index 2f9235d8..c74e9773 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -33,7 +33,6 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-security/utils" - "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-client-go/artifactory/services/fspatterns" clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/errorutils" @@ -527,13 +526,6 @@ func getXrayRepoPathFromTarget(target string) (repoPath string) { return target[:strings.LastIndex(target, "/")+1] } -func appendErrorSlice(scanErrors []formats.SimpleJsonError, errorsToAdd [][]formats.SimpleJsonError) []formats.SimpleJsonError { - for _, errorSlice := range errorsToAdd { - scanErrors = append(scanErrors, errorSlice...) - } - return scanErrors -} - func directDepsListFromVulnerabilities(scanResult ...services.ScanResponse) *[]string { depsList := []string{} for _, result := range scanResult { From c9c2933e82d75b8371d43c29fc7168922333c56e Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 14 Jul 2024 18:33:27 +0300 Subject: [PATCH 12/82] continue refactor for tests --- audit_test.go | 149 +- commands/audit/scarunner.go | 3 +- commands/scan/buildscan.go | 2 +- commands/scan/scan.go | 2 +- jas/runner/jasrunner_test.go | 2 +- jfrogclisecurity_test.go | 3 +- scans_test.go | 38 +- .../other/output/formats/audit_results.json | 1666 +++++++++++++++++ .../other/output/formats/audit_sarif.json | 1291 +++++++++++++ .../output/formats/audit_simple_json.json | 883 +++++++++ .../other/output/formats/audit_summary.json | 0 .../other/output/formats/audit_table.json | 0 .../jobSummary/multi_command_job.md | 0 .../{ => output}/jobSummary/single_issue.md | 0 .../jobSummary/single_no_issue.md | 0 tests/utils/test_config.go | 5 +- tests/utils/test_utils.go | 34 +- tests/utils/test_validation.go | 94 - utils/results/conversion/convertor_test.go | 153 ++ .../conversion/sarifparser/sarifparser.go | 8 +- .../simplejsonparser/simplejsonparser.go | 33 +- .../simplejsonparser/simplejsonparser_test.go | 4 +- .../conversion/summaryparser/summaryparser.go | 50 +- .../conversion/tableparser/tableparser.go | 2 +- .../results/output/securityJobSummary_test.go | 14 +- utils/results/results.go | 7 +- utils/{ => validations}/test_mocks.go | 2 +- utils/validations/test_validate_sarif.go | 86 + utils/validations/test_validate_sca.go | 90 + .../validations/test_validate_simple_json.go | 240 +++ utils/validations/test_validate_summary.go | 26 + utils/validations/test_validate_table.go | 36 + utils/validations/test_validation.go | 133 ++ utils/xsc/analyticsmetrics_test.go | 15 +- utils/xsc/errorreport_test.go | 10 +- xsc_test.go | 21 +- 36 files changed, 4882 insertions(+), 220 deletions(-) create mode 100644 tests/testdata/other/output/formats/audit_results.json create mode 100644 tests/testdata/other/output/formats/audit_sarif.json create mode 100644 tests/testdata/other/output/formats/audit_simple_json.json create mode 100644 tests/testdata/other/output/formats/audit_summary.json create mode 100644 tests/testdata/other/output/formats/audit_table.json rename tests/testdata/other/{ => output}/jobSummary/multi_command_job.md (100%) rename tests/testdata/other/{ => output}/jobSummary/single_issue.md (100%) rename tests/testdata/other/{ => output}/jobSummary/single_no_issue.md (100%) delete mode 100644 tests/utils/test_validation.go create mode 100644 utils/results/conversion/convertor_test.go rename utils/{ => validations}/test_mocks.go (98%) create mode 100644 utils/validations/test_validate_sarif.go create mode 100644 utils/validations/test_validate_sca.go create mode 100644 utils/validations/test_validate_simple_json.go create mode 100644 utils/validations/test_validate_summary.go create mode 100644 utils/validations/test_validate_table.go create mode 100644 utils/validations/test_validation.go diff --git a/audit_test.go b/audit_test.go index a15515aa..2403d95d 100644 --- a/audit_test.go +++ b/audit_test.go @@ -14,6 +14,7 @@ import ( "github.com/jfrog/jfrog-cli-security/cli" "github.com/jfrog/jfrog-cli-security/cli/docs" "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/validations" xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" @@ -34,12 +35,18 @@ import ( func TestXrayAuditNpmJson(t *testing.T) { output := testAuditNpm(t, string(format.Json)) - securityTestUtils.VerifyJsonScanResults(t, output, 1, 0, 1) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + SecurityViolations: 1, + Licenses: 1, + }) } func TestXrayAuditNpmSimpleJson(t *testing.T) { output := testAuditNpm(t, string(format.SimpleJson)) - securityTestUtils.VerifySimpleJsonScanResults(t, output, 1, 0, 1) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + SecurityViolations: 1, + Licenses: 1, + }) } func testAuditNpm(t *testing.T, format string) string { @@ -62,12 +69,18 @@ func testAuditNpm(t *testing.T, format string) string { func TestXrayAuditPnpmJson(t *testing.T) { output := testXrayAuditPnpm(t, string(format.Json)) - securityTestUtils.VerifyJsonScanResults(t, output, 0, 1, 1) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) } func TestXrayAuditPnpmSimpleJson(t *testing.T) { output := testXrayAuditPnpm(t, string(format.SimpleJson)) - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 1, 1) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) } func testXrayAuditPnpm(t *testing.T, format string) string { @@ -89,21 +102,30 @@ func testXrayAuditPnpm(t *testing.T, format string) string { func TestXrayAuditYarnV2Json(t *testing.T) { testXrayAuditYarn(t, "yarn-v2", func() { output := runXrayAuditYarnWithOutput(t, string(format.Json)) - securityTestUtils.VerifyJsonScanResults(t, output, 0, 1, 1) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) }) } func TestXrayAuditYarnV2SimpleJson(t *testing.T) { testXrayAuditYarn(t, "yarn-v3", func() { output := runXrayAuditYarnWithOutput(t, string(format.SimpleJson)) - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 1, 1) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) }) } func TestXrayAuditYarnV1Json(t *testing.T) { testXrayAuditYarn(t, "yarn-v1", func() { output := runXrayAuditYarnWithOutput(t, string(format.Json)) - securityTestUtils.VerifyJsonScanResults(t, output, 0, 1, 1) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) }) } @@ -122,7 +144,10 @@ func TestXrayAuditYarnV1JsonWithoutDevDependencies(t *testing.T) { func TestXrayAuditYarnV1SimpleJson(t *testing.T) { testXrayAuditYarn(t, "yarn-v1", func() { output := runXrayAuditYarnWithOutput(t, string(format.SimpleJson)) - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 1, 1) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) }) } @@ -196,7 +221,10 @@ func TestXrayAuditNugetJson(t *testing.T) { t.Run(fmt.Sprintf("projectName:%s,runInstallCommand:%t", test.projectName, runInstallCommand), func(t *testing.T) { output := testXrayAuditNuget(t, test.projectName, test.format, test.restoreTech) - securityTestUtils.VerifyJsonScanResults(t, output, 0, test.minVulnerabilities, test.minLicences) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: test.minVulnerabilities, + Licenses: test.minLicences, + }) }) } } @@ -236,7 +264,10 @@ func TestXrayAuditNugetSimpleJson(t *testing.T) { t.Run(fmt.Sprintf("projectName:%s,runInstallCommand:%t", test.projectName, runInstallCommand), func(t *testing.T) { output := testXrayAuditNuget(t, test.projectName, test.format, test.restoreTech) - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, test.minVulnerabilities, test.minLicences) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: test.minVulnerabilities, + Licenses: test.minLicences, + }) }) } } @@ -262,12 +293,18 @@ func testXrayAuditNuget(t *testing.T, projectName, format string, restoreTech st func TestXrayAuditGradleJson(t *testing.T) { output := testXrayAuditGradle(t, string(format.Json)) - securityTestUtils.VerifyJsonScanResults(t, output, 0, 3, 3) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 3, + Licenses: 3, + }) } func TestXrayAuditGradleSimpleJson(t *testing.T) { output := testXrayAuditGradle(t, string(format.SimpleJson)) - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 3, 3) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 3, + Licenses: 3, + }) } func testXrayAuditGradle(t *testing.T, format string) string { @@ -286,12 +323,12 @@ func testXrayAuditGradle(t *testing.T, format string) string { func TestXrayAuditMavenJson(t *testing.T) { output := testXscAuditMaven(t, string(format.Json)) - securityTestUtils.VerifyJsonScanResults(t, output, 0, 1, 1) + validations.VerifyJsonScanResults(t, output, 0, 1, 1) } func TestXrayAuditMavenSimpleJson(t *testing.T) { output := testXscAuditMaven(t, string(format.SimpleJson)) - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 1, 1) + validations.VerifySimpleJsonScanResults(t, output, 0, 1, 1) } func testXscAuditMaven(t *testing.T, format string) string { @@ -335,28 +372,40 @@ func TestXrayAuditMultiProjects(t *testing.T) { securityTestUtils.CreateJfrogHomeConfig(t, true) defer securityTestUtils.CleanTestsHomeEnv() output := securityTests.PlatformCli.WithoutCredentials().RunCliCmdWithOutput(t, "audit", "--format="+string(format.SimpleJson), workingDirsFlag) - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 35, 0) - securityTestUtils.VerifySimpleJsonJasResults(t, output, 1, 9, 6, 3, 0, 25, 2) + + VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Sast: 1, + Iac: 9, + Secrets: 6, + + Vulnerabilities: 35, + Applicable: 3, + Undetermined: 0, + NotCovered: 25, + NotApplicable: 2, + }) + // validations.VerifySimpleJsonScanResults(t, output, 0, 35, 0) + // validations.VerifySimpleJsonJasResults(t, output, 1, 9, 6, 3, 0, 25, 2) } func TestXrayAuditPipJson(t *testing.T) { output := testXrayAuditPip(t, string(format.Json), "") - securityTestUtils.VerifyJsonScanResults(t, output, 0, 3, 1) + validations.VerifyJsonScanResults(t, output, 0, 3, 1) } func TestXrayAuditPipSimpleJson(t *testing.T) { output := testXrayAuditPip(t, string(format.SimpleJson), "") - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 3, 1) + validations.VerifySimpleJsonScanResults(t, output, 0, 3, 1) } func TestXrayAuditPipJsonWithRequirementsFile(t *testing.T) { output := testXrayAuditPip(t, string(format.Json), "requirements.txt") - securityTestUtils.VerifyJsonScanResults(t, output, 0, 2, 0) + validations.VerifyJsonScanResults(t, output, 0, 2, 0) } func TestXrayAuditPipSimpleJsonWithRequirementsFile(t *testing.T) { output := testXrayAuditPip(t, string(format.SimpleJson), "requirements.txt") - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 2, 0) + validations.VerifySimpleJsonScanResults(t, output, 0, 2, 0) } func testXrayAuditPip(t *testing.T, format, requirementsFile string) string { @@ -380,12 +429,12 @@ func testXrayAuditPip(t *testing.T, format, requirementsFile string) string { func TestXrayAuditPipenvJson(t *testing.T) { output := testXrayAuditPipenv(t, string(format.Json)) - securityTestUtils.VerifyJsonScanResults(t, output, 0, 3, 1) + validations.VerifyJsonScanResults(t, output, 0, 3, 1) } func TestXrayAuditPipenvSimpleJson(t *testing.T) { output := testXrayAuditPipenv(t, string(format.SimpleJson)) - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 3, 1) + validations.VerifySimpleJsonScanResults(t, output, 0, 3, 1) } func testXrayAuditPipenv(t *testing.T, format string) string { @@ -404,12 +453,12 @@ func testXrayAuditPipenv(t *testing.T, format string) string { func TestXrayAuditPoetryJson(t *testing.T) { output := testXrayAuditPoetry(t, string(format.Json)) - securityTestUtils.VerifyJsonScanResults(t, output, 0, 3, 1) + validations.VerifyJsonScanResults(t, output, 0, 3, 1) } func TestXrayAuditPoetrySimpleJson(t *testing.T) { output := testXrayAuditPoetry(t, string(format.SimpleJson)) - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 3, 1) + validations.VerifySimpleJsonScanResults(t, output, 0, 3, 1) } func testXrayAuditPoetry(t *testing.T, format string) string { @@ -442,10 +491,11 @@ func TestXrayAuditNotEntitledForJas(t *testing.T) { cliToRun, cleanUp := securityTestUtils.InitTestWithMockCommandOrParams(t, getNoJasAuditMockCommand) defer cleanUp() output := testXrayAuditJas(t, cliToRun, filepath.Join("jas", "jas"), "3") + VerifySimpleJsonResults(t, output, validations.ValidationParams{Vulnerabilities: 8}) // Verify that scan results are printed - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 8, 0) + // validations.VerifySimpleJsonScanResults(t, output, 0, 8, 0) // Verify that JAS results are not printed - securityTestUtils.VerifySimpleJsonJasResults(t, output, 0, 0, 0, 0, 0, 0, 0) + // validations.VerifySimpleJsonJasResults(t, output, 0, 0, 0, 0, 0, 0, 0) } func getNoJasAuditMockCommand(t *testing.T) components.Command { @@ -466,25 +516,52 @@ func getNoJasAuditMockCommand(t *testing.T) components.Command { func TestXrayAuditJasSimpleJson(t *testing.T) { output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("jas", "jas"), "3") - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 8, 0) - securityTestUtils.VerifySimpleJsonJasResults(t, output, 1, 9, 6, 3, 0, 2, 2) + VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Sast: 1, + Iac: 9, + Secrets: 6, + + Vulnerabilities: 8, + Applicable: 3, + NotCovered: 2, + NotApplicable: 2, + }) + // validations.VerifySimpleJsonScanResults(t, output, 0, 8, 0) + // validations.VerifySimpleJsonJasResults(t, output, 1, 9, 6, 3, 0, 2, 2) } func TestXrayAuditJasSimpleJsonWithOneThread(t *testing.T) { output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("jas", "jas"), "1") - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 8, 0) - securityTestUtils.VerifySimpleJsonJasResults(t, output, 1, 9, 6, 3, 0, 2, 2) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Sast: 1, + Iac: 9, + Secrets: 6, + + Vulnerabilities: 8, + Applicable: 3, + NotCovered: 2, + NotApplicable: 2, + }) } func TestXrayAuditJasSimpleJsonWithConfig(t *testing.T) { output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("jas", "jas-config"), "3") - securityTestUtils.VerifySimpleJsonJasResults(t, output, 0, 0, 1, 3, 0, 2, 2) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Secrets: 1, + + Vulnerabilities: 8, + Applicable: 3, + NotCovered: 2, + NotApplicable: 2, + }) } func TestXrayAuditJasNoViolationsSimpleJson(t *testing.T) { output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("package-managers", "npm", "npm"), "3") - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 1, 0) - securityTestUtils.VerifySimpleJsonJasResults(t, output, 0, 0, 0, 0, 0, 0, 1) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + NotApplicable: 1, + }) } func testXrayAuditJas(t *testing.T, testCli *coreTests.JfrogCli, project string, threads string) string { @@ -549,7 +626,7 @@ func TestXrayRecursiveScan(t *testing.T) { output := securityTests.PlatformCli.RunCliCmdWithOutput(t, "audit", "--format=json") // We anticipate the identification of five vulnerabilities: four originating from the .NET project and one from the NPM project. - securityTestUtils.VerifyJsonScanResults(t, output, 0, 4, 0) + validations.VerifyJsonResults(t, output, validations.ValidationParams{Vulnerabilities: 4}) var results []services.ScanResponse err = json.Unmarshal([]byte(output), &results) @@ -573,5 +650,7 @@ func TestAuditOnEmptyProject(t *testing.T) { chdirCallback := clientTests.ChangeDirWithCallback(t, baseWd, tempDirPath) defer chdirCallback() output := securityTests.PlatformCli.WithoutCredentials().RunCliCmdWithOutput(t, "audit", "--format="+string(format.SimpleJson)) - securityTestUtils.VerifySimpleJsonJasResults(t, output, 0, 0, 0, 0, 0, 0, 0) + // No issues should be found in an empty project + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{}) } + diff --git a/commands/audit/scarunner.go b/commands/audit/scarunner.go index 08275356..1ca553ca 100644 --- a/commands/audit/scarunner.go +++ b/commands/audit/scarunner.go @@ -149,10 +149,9 @@ func executeScaScanTask(auditParallelRunner *utils.SecurityParallelRunner, serve if xrayErr != nil { return fmt.Errorf("%s Xray dependency tree scan request on '%s' failed:\n%s", clientutils.GetLogMsgPrefix(threadId, false), scan.Technology, xrayErr.Error()) } - scan.ScaResults.IsMultipleRootProject = clientutils.Pointer(len(treeResult.FullDepTrees) > 1) auditParallelRunner.ResultsMu.Lock() + scan.NewScaScanResults(scanResults...).IsMultipleRootProject = clientutils.Pointer(len(treeResult.FullDepTrees) > 1) addThirdPartyDependenciesToParams(auditParams, scan.Technology, treeResult.FlatTree, treeResult.FullDepTrees) - scan.ScaResults.XrayResults = append(scan.ScaResults.XrayResults, scanResults...) auditParallelRunner.ResultsMu.Unlock() return } diff --git a/commands/scan/buildscan.go b/commands/scan/buildscan.go index 998acc2c..d55b382b 100644 --- a/commands/scan/buildscan.go +++ b/commands/scan/buildscan.go @@ -126,7 +126,7 @@ func (bsc *BuildScanCommand) runBuildScanAndPrintResults(xrayManager *xray.XrayS cmdResults := results.NewCommandResults(xrayVersion, false) scanResults := cmdResults.NewScanResults(results.ScanTarget{Name: fmt.Sprintf("%s (%s)", params.BuildName, params.BuildNumber)}) - scanResults.NewScaScanResults(&services.ScanResponse{ + scanResults.NewScaScanResults(services.ScanResponse{ Violations: buildScanResults.Violations, Vulnerabilities: buildScanResults.Vulnerabilities, XrayDataUrl: buildScanResults.MoreDetailsUrl, diff --git a/commands/scan/scan.go b/commands/scan/scan.go index c74e9773..8f156e09 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -386,7 +386,7 @@ func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, cmdResults targetResults.AddError(err) return } else { - targetResults.NewScaScanResults(graphScanResults) + targetResults.NewScaScanResults(*graphScanResults) targetResults.Technology = techutils.Technology(graphScanResults.ScannedPackageType) } if !cmdResults.EntitledForJas { diff --git a/jas/runner/jasrunner_test.go b/jas/runner/jasrunner_test.go index e3a4ace4..47d309f1 100644 --- a/jas/runner/jasrunner_test.go +++ b/jas/runner/jasrunner_test.go @@ -42,7 +42,7 @@ func TestGetExtendedScanResults_ServerNotValid(t *testing.T) { jasScanner, err := jas.CreateJasScanner(scanner, &jas.FakeServerDetails, jas.GetAnalyzerManagerXscEnvVars("", targetResults.GetTechnologies()...)) assert.NoError(t, err) - targetResults.NewScaScanResults(&jas.FakeBasicXrayResults[0]) + targetResults.NewScaScanResults(jas.FakeBasicXrayResults[0]) err = AddJasScannersTasks(securityParallelRunnerForTest, jfrogappsconfig.Module{}, targetResults, &[]string{"issueId_1_direct_dependency", "issueId_2_direct_dependency"}, nil, false, jasScanner, applicability.ApplicabilityScannerType, secrets.SecretsScannerType, utils.GetAllSupportedScans()) assert.NoError(t, err) } diff --git a/jfrogclisecurity_test.go b/jfrogclisecurity_test.go index 94253546..d8be3833 100644 --- a/jfrogclisecurity_test.go +++ b/jfrogclisecurity_test.go @@ -6,6 +6,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-core/v2/utils/log" + "github.com/jfrog/jfrog-cli-security/cli" "github.com/jfrog/jfrog-cli-security/tests/utils" configTests "github.com/jfrog/jfrog-cli-security/tests" @@ -38,7 +39,7 @@ func setupIntegrationTests() { flag.Parse() log.SetDefaultLogger() // Init - utils.InitTestCliDetails() + utils.InitTestCliDetails(cli.GetJfrogCliSecurityApp()) utils.AuthenticateArtifactory() utils.AuthenticateXsc() utils.CreateRequiredRepositories() diff --git a/scans_test.go b/scans_test.go index 0e1f6088..bfe9cdc4 100644 --- a/scans_test.go +++ b/scans_test.go @@ -3,8 +3,6 @@ package main import ( "encoding/json" "fmt" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "net/http" "net/http/httptest" "os" @@ -14,9 +12,13 @@ import ( "sync" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + biutils "github.com/jfrog/build-info-go/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/validations" "github.com/jfrog/jfrog-cli-security/cli" "github.com/jfrog/jfrog-cli-security/cli/docs" @@ -47,26 +49,38 @@ import ( func TestXrayBinaryScanJson(t *testing.T) { output := testXrayBinaryScan(t, string(format.Json)) - securityTestUtils.VerifyJsonScanResults(t, output, 0, 1, 1) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) } func TestXrayBinaryScanSimpleJson(t *testing.T) { output := testXrayBinaryScan(t, string(format.SimpleJson)) - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 1, 1) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) } func TestXrayBinaryScanJsonWithProgress(t *testing.T) { callback := commonTests.MockProgressInitialization() defer callback() output := testXrayBinaryScan(t, string(format.Json)) - securityTestUtils.VerifyJsonScanResults(t, output, 0, 1, 1) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) } func TestXrayBinaryScanSimpleJsonWithProgress(t *testing.T) { callback := commonTests.MockProgressInitialization() defer callback() output := testXrayBinaryScan(t, string(format.SimpleJson)) - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 1, 1) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) } func testXrayBinaryScan(t *testing.T, format string) string { @@ -89,7 +103,10 @@ func TestXrayBinaryScanWithBypassArchiveLimits(t *testing.T) { // Run with bypass flag and expect it to find vulnerabilities scanArgs = append(scanArgs, "--bypass-archive-limits") output := securityTests.PlatformCli.RunCliCmdWithOutput(t, scanArgs...) - securityTestUtils.VerifyJsonScanResults(t, output, 0, 1, 1) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) } // Docker scan tests @@ -170,7 +187,10 @@ func runDockerScan(t *testing.T, testCli *coreTests.JfrogCli, imageName, watchNa cmdArgs := []string{"docker", "scan", imageTag, "--server-id=default", "--licenses", "--format=json", "--fail=false", "--min-severity=low", "--fixable-only"} output := testCli.WithoutCredentials().RunCliCmdWithOutput(t, cmdArgs...) if assert.NotEmpty(t, output) { - securityTestUtils.VerifyJsonScanResults(t, output, 0, minVulnerabilities, minLicenses) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: minVulnerabilities, + Licenses: minLicenses, + }) } // Run docker scan on image with watch if watchName == "" { @@ -179,7 +199,7 @@ func runDockerScan(t *testing.T, testCli *coreTests.JfrogCli, imageName, watchNa cmdArgs = append(cmdArgs, "--watches="+watchName) output = testCli.WithoutCredentials().RunCliCmdWithOutput(t, cmdArgs...) if assert.NotEmpty(t, output) { - securityTestUtils.VerifyJsonScanResults(t, output, minViolations, 0, 0) + validations.VerifyJsonResults(t, output, validations.ValidationParams{SecurityViolations: minViolations}) } } } diff --git a/tests/testdata/other/output/formats/audit_results.json b/tests/testdata/other/output/formats/audit_results.json new file mode 100644 index 00000000..1c71d750 --- /dev/null +++ b/tests/testdata/other/output/formats/audit_results.json @@ -0,0 +1,1666 @@ +{ + "xray_version": "3.98.2", + "jas_entitled": true, + "targets": [ + { + "target": "/Users/user/ejs-frog-demo", + "technology": "npm", + "sca_scans": { + "is_multiple_root_project": false, + "xray_scan": [ + { + "scan_id": "3d90ec4b-cf33-4846-6831-4bf9576f2235", + "vulnerabilities": [ + { + "cves": [ + { + "cve": "CVE-2019-1010266", + "cvss_v2_score": "4.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:S/C:N/I:N/A:P", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-400", + "CWE-770" + ], + "cwe_details": { + "CWE-400": { + "name": "Uncontrolled Resource Consumption", + "description": "The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources." + }, + "CWE-770": { + "name": "Allocation of Resources Without Limits or Throttling", + "description": "The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor." + } + } + } + ], + "summary": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", + "severity": "Medium", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.11]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "issue_id": "XRAY-85049" + }, + { + "cves": [ + { + "cve": "CVE-2020-28500", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "cwe": [ + "CWE-400", + "CWE-1333", + "NVD-CWE-Other" + ], + "cwe_details": { + "CWE-1333": { + "name": "Inefficient Regular Expression Complexity", + "description": "The product uses a regular expression with an inefficient, possibly exponential worst-case computational complexity that consumes excessive CPU cycles." + }, + "CWE-400": { + "name": "Uncontrolled Resource Consumption", + "description": "The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources." + } + } + } + ], + "summary": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", + "severity": "Medium", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.21]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "issue_id": "XRAY-140562", + "extended_information": { + "short_description": "ReDoS in lodash could lead to a denial of service when handling untrusted strings.", + "full_description": "JavaScript-based applications that use [lodash](https://github.com/lodash/lodash) and specifically the [_.toNumber](https://lodash.com/docs/4.17.15#toNumber), [_.trim](https://lodash.com/docs/4.17.15#trim) and [_.trimEnd](https://lodash.com/docs/4.17.15#trimEnd) functions, could be vulnerable to DoS (Denial of Service) through a faulty regular expression that introduces a ReDoS (Regular Expression DoS) vulnerability. This vulnerability is only triggered if untrusted user input flows into these vulnerable functions and the attacker can supply arbitrary long strings (over 50kB) that contain whitespaces. \n\nOn a modern Core i7-based system, calling the vulnerable functions with a 50kB string could take between 2 to 3 seconds to execute and 4.5 minutes for a longer 500kB string. The fix improved the regular expression performance so it took only a few milliseconds on the same Core i7-based system. This vulnerability is easily exploitable as all is required is to build a string that triggers it as can be seen in this PoC reproducing code - \n\n```js\nvar untrusted_user_input_50k = \"a\" + ' '.repeat(50000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_50k); // should take a few seconds to run\nvar untrusted_user_input_500k = \"a\" + ' '.repeat(500000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_500k); // should take a few minutes to run\n```", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "Public exploit demonstrated ReDoS" + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "Exploitation depends on parsing user input by the `.toNumber`, `.trim` or `.trimEnd` `lodash` functions, and requires the input to contain whitespaces and be very long (over 50KB)", + "is_positive": true + } + ], + "remediation": "##### Deployment mitigations\n\nTrim untrusted strings based on size before providing it to the vulnerable functions by using the `substring` function to with a fixed maximum size like so - ```js untrusted_user_input.substring(0, max_string_size_less_than_50kB); ```" + } + }, + { + "cves": [ + { + "cve": "CVE-2018-3721", + "cvss_v2_score": "4.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:S/C:N/I:P/A:N", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N", + "cwe": [ + "CWE-1321", + "CWE-471" + ], + "cwe_details": { + "CWE-1321": { + "name": "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')", + "description": "The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype." + }, + "CWE-471": { + "name": "Modification of Assumed-Immutable Data (MAID)", + "description": "The product does not properly protect an assumed-immutable element from being modified by an attacker." + } + } + } + ], + "summary": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", + "severity": "Medium", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.5]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "issue_id": "XRAY-72918" + }, + { + "cves": [ + { + "cve": "CVE-2020-8203", + "cvss_v2_score": "5.8", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:P/A:P", + "cvss_v3_score": "7.4", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:H", + "cwe": [ + "CWE-770", + "CWE-1321" + ], + "cwe_details": { + "CWE-1321": { + "name": "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')", + "description": "The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype." + }, + "CWE-770": { + "name": "Allocation of Resources Without Limits or Throttling", + "description": "The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor." + } + } + } + ], + "summary": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", + "severity": "High", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.19]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "issue_id": "XRAY-114089", + "extended_information": { + "short_description": "Prototype pollution in lodash object merging and zipping functions leads to code injection.", + "full_description": "[lodash](https://lodash.com/) is a JavaScript library which provides utility functions for common programming tasks.\n\nJavaScript frontend and Node.js-based backend applications that merge or zip objects using the lodash functions `mergeWith`, `merge` and `zipObjectDeep` are vulnerable to [prototype pollution](https://medium.com/node-modules/what-is-prototype-pollution-and-why-is-it-such-a-big-deal-2dd8d89a93c) if one or more of the objects it receives as arguments are obtained from user input. \nAn attacker controlling this input given to the vulnerable functions can inject properties to JavaScript special objects such as [Object.prototype](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes) from which all JavaScript objects inherit properties and methods. Any change on `Object.prototype` properties will then propagate through the prototype chain inheritance to all of the objects in a JavaScript application. This in turn would allow an attacker to add new properties or modify existing properties which will have application specific implications that could lead to DoS (denial of service), authentication bypass, privilege escalation and even RCE (remote code execution) in [some cases](https://youtu.be/LUsiFV3dsK8?t=1152). \nAs an example for privilege escalation, consider a JavaScript application that has a `user` object which has a Boolean property of `user.isAdmin` which is used to decide which actions the user may take. If an attacker can modify or add the `isAdmin` property through prototype pollution, it can escalate the privileges of its own user to those of an admin. \nAs exploitation is usually application specific, successful exploitation is much more likely if an attacker have access to the JavaScript application code. As such, frontend applications are more vulnerable to this vulnerability than Node.js backend applications.", + "jfrog_research_severity": "Critical", + "jfrog_research_severity_reasons": [ + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "is_positive": true + }, + { + "name": "The issue can be exploited by attackers over the network" + }, + { + "name": "The issue is trivial to exploit and does not require a published writeup or PoC" + } + ], + "remediation": "##### Deployment mitigations\n\nAs general guidelines against prototype pollution, first consider not merging objects originating from user input or using a Map structure instead of an object. If merging objects is needed, look into creating objects without a prototype with `Object.create(null)` or into freezing `Object.prototype` with `Object.freeze()`. Finally, it is always best to perform input validation with a a [JSON schema validator](https://github.com/ajv-validator/ajv), which could mitigate this issue entirely in many cases." + } + }, + { + "cves": [ + { + "cve": "CVE-2021-23337", + "cvss_v2_score": "6.5", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:S/C:P/I:P/A:P", + "cvss_v3_score": "7.2", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-77", + "CWE-94" + ], + "cwe_details": { + "CWE-77": { + "name": "Improper Neutralization of Special Elements used in a Command ('Command Injection')", + "description": "The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "16" + } + ] + }, + "CWE-94": { + "name": "Improper Control of Generation of Code ('Code Injection')", + "description": "The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "23" + } + ] + } + } + } + ], + "summary": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", + "severity": "High", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.21]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "issue_id": "XRAY-140575", + "extended_information": { + "short_description": "Improper sanitization in the lodash template function leads to JavaScript code injection through the options argument.", + "full_description": "JavaScript-based applications (both frontend and backend) that use the [template function](https://lodash.com/docs/4.17.15#template) -`_.template([string=''], [options={}])` from the [lodash](https://lodash.com/) utility library and provide the `options` argument (specifically the `variable` option) from untrusted user input, are vulnerable to JavaScript code injection. This issue can be easily exploited, and an exploitation example is [publicly available](https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c#diff-a561630bb56b82342bc66697aee2ad96efddcbc9d150665abd6fb7ecb7c0ab2fR22303) in the fix tests that was introduced in version 4.17.21 - \n```js\nlodash.template('', { variable: '){console.log(process.env)}; with(obj' })()\n```", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "It is highly unlikely that a JS program will accept arbitrary remote input into the template's `options` argument", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must find remote input that propagates into the `options` argument of a `template` call", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Leads to remote code execution through JS code injection" + }, + { + "name": "The issue has an exploit published", + "description": "Published exploit demonstrates arbitrary JS code execution" + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2018-16487", + "cvss_v2_score": "6.8", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:P/I:P/A:P", + "cvss_v3_score": "5.6", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L", + "cwe": [ + "CWE-400", + "NVD-CWE-noinfo" + ], + "cwe_details": { + "CWE-400": { + "name": "Uncontrolled Resource Consumption", + "description": "The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources." + } + } + } + ], + "summary": "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": "Medium", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.11]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "issue_id": "XRAY-75300", + "extended_information": { + "short_description": "Insufficient input validation in the Lodash library leads to prototype pollution.", + "full_description": "The [Lodash](https://lodash.com/) library is an open-source JavaScript project that simplifies operations on string, arrays, numbers, and other objects. It is widely used in connected devices. \n\nThe `merge`, `mergeWith`, and `defaultsDeep` methods in Lodash are vulnerable to [prototype pollution](https://shieldfy.io/security-wiki/prototype-pollution/introduction-to-prototype-pollution/). Attackers can exploit this vulnerability by specifying a crafted `sources` parameter to any of these methods, which can modify the prototype properties of the `Object`, `Function`, `Array`, `String`, `Number`, and `Boolean` objects. A public [exploit](https://hackerone.com/reports/380873) exists which performs the prototype pollution with an arbitrary key and value.\n\nThe library implementation has a bug in the `safeGet()` function in the `lodash.js` module that allows for adding or modifying `prototype` properties of various objects. The official [solution](https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad) fixes the bug by explicitly forbidding the addition or modification of `prototype` properties.\n\nA related CVE (CVE-2018-3721) covers the same issue prior to Lodash version 4.17.5, but the fix for that was incomplete.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find remote input that propagates into one of the following methods - \n* `merge` - 2nd argument\n* `mergeWith` - 2nd argument\n* `defaultsDeep` - 2nd argument", + "is_positive": true + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "A public PoC demonstrated exploitation by injecting an attacker controlled key and value into the prototype" + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." + } + }, + { + "cves": [ + { + "cve": "CVE-2019-10744", + "cvss_v2_score": "6.4", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:P/A:P", + "cvss_v3_score": "9.1", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H", + "cwe": [ + "CWE-1321", + "CWE-20" + ], + "cwe_details": { + "CWE-1321": { + "name": "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')", + "description": "The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype." + }, + "CWE-20": { + "name": "Improper Input Validation", + "description": "The product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "6" + } + ] + } + } + } + ], + "summary": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", + "severity": "Critical", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.12]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "issue_id": "XRAY-85679", + "extended_information": { + "short_description": "Insufficient input validation in lodash defaultsDeep() leads to prototype pollution.", + "full_description": "[lodash](https://www.npmjs.com/package/lodash) is a modern JavaScript utility library delivering modularity, performance, \u0026 extras.\n\nThe function `defaultsDeep` was found to be vulnerable to prototype pollution, when accepting arbitrary source objects from untrusted input\n\nExample of code vulnerable to this issue - \n```js\nconst lodash = require('lodash'); \nconst evilsrc = {constructor: {prototype: {evilkey: \"evilvalue\"}}};\nlodash.defaultsDeep({}, evilsrc)\n```", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "A public PoC demonstrates exploitation of this issue" + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find remote input that propagates into the `defaultsDeep` method (2nd arg)", + "is_positive": true + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." + } + }, + { + "cves": [ + { + "cve": "CVE-2024-29041", + "cvss_v3_score": "6.1", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N", + "cwe": [ + "CWE-601", + "CWE-1286" + ], + "cwe_details": { + "CWE-1286": { + "name": "Improper Validation of Syntactic Correctness of Input", + "description": "The product receives input that is expected to be well-formed - i.e., to comply with a certain syntax - but it does not validate or incorrectly validates that the input complies with the syntax." + }, + "CWE-601": { + "name": "URL Redirection to Untrusted Site ('Open Redirect')", + "description": "A web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a Redirect. This simplifies phishing attacks." + } + } + } + ], + "summary": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", + "severity": "Medium", + "components": { + "npm://express:4.18.2": { + "fixed_versions": [ + "[4.19.2]", + "[5.0.0-beta.3]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://express:4.18.2" + } + ] + ] + } + }, + "issue_id": "XRAY-594935" + }, + { + "cves": [ + { + "cve": "CVE-2024-39249" + } + ], + "summary": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", + "severity": "Unknown", + "components": { + "npm://async:3.2.4": { + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://ejs:3.1.6" + }, + { + "component_id": "npm://jake:10.8.7" + }, + { + "component_id": "npm://async:3.2.4" + } + ] + ] + } + }, + "issue_id": "XRAY-609848", + "extended_information": { + "short_description": "ReDoS in Async may lead to denial of service while parsing malformed source code.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The reported CVSS does not reflect the severity of the vulnerability.", + "is_positive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "To exploit this issue an attacker must change the source code of the application. In cases where an attacker can already modify (or fully control) the source code, the attacker can immediately achieve arbitrary code execution - thus this issue has almost no security impact.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "A proof-of-concept has been published in the advisory." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The issue requires the use of the `async.autoInject` function to be vulnerable.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2024-33883", + "cwe": [ + "CWE-1321" + ], + "cwe_details": { + "CWE-1321": { + "name": "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')", + "description": "The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype." + } + } + } + ], + "summary": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", + "severity": "Medium", + "components": { + "npm://ejs:3.1.6": { + "fixed_versions": [ + "[3.1.10]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://ejs:3.1.6" + } + ] + ] + } + }, + "issue_id": "XRAY-599735", + "extended_information": { + "short_description": "Insufficient input validation in EJS may lead to prototype pollution.", + "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as `EJS`, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nA prototype pollution gadget within the EJS template engine could potentially be leveraged by attackers to achieve remote code execution or DoS via prototype pollution.\n\n```\nfunction Template(text, opts) {\n opts = opts || utils.createNullProtoObjWherePossible();\n```\n\nWhen checking for the presence of a property within an object variable, the lookup scope isn't explicitly defined. In JavaScript, the absence of a defined lookup scope prompts a search up to the root prototype (`Object.prototype`). This could potentially be under the control of an attacker if another prototype pollution vulnerability is present within the application.\n\nIf the application server is using the EJS as the backend template engine, and there is another prototype pollution vulnerability in the application, then the attacker could leverage the found gadgets in the EJS template engine to escalate the prototype pollution to remote code execution or DoS.\n\nThe following code will execute a command on the server by polluting `opts.escapeFunction`:\n \n```\nconst express = require('express');\nconst app = express();\nconst port = 8008;\nconst ejs = require('ejs');\n\n// Set EJS as the view engine\napp.set('view engine', 'ejs');\n\napp.get('/', (req, res) =\u003e {\n \n const data = {title: 'Welcome', message: 'Hello'};\n\n // Sample EJS template string\n const templateString = `\u003chtml\u003e\u003chead\u003e\u003ctitle\u003e\u003c%= title %\u003e\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003ch1\u003e\u003c%= message %\u003e\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e`;\n\n const { exec } = require('child_process');\n\n function myFunc() {\n exec('bash -c \"echo 123\"', (error, stdout, stderr) =\u003e {\n if (error) {\n console.error(`exec error: ${error}`);\n return;\n }\n if (stderr){\n console.log(`stderr : ${stderr}`);\n return;\n }\n // Handle success\n console.log(`Command executed successfully. Output: ${stdout}`);\n });\n }\n\n const options = {client:false};\n\n Object.prototype.escapeFunction = myFunc;\n \n const compiledTemplate = ejs.compile(templateString, options);\n const renderedHtml = compiledTemplate(data);\n res.send(renderedHtml);\n});\n\n// Start the server\napp.listen(port, () =\u003e {\n console.log(`Server is running on http://localhost:${port}`);\n});\n```", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "Attackers can only leverage this vulnerability when the application server is using the EJS as the backend template engine. Moreover, there must be a second prototype pollution vulnerability in the application.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "CVSS does not take into account the unlikely prerequisites necessary for exploitation.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "A prototype pollution attack allows the attacker to inject new properties into all JavaScript objects.\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable." + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-29827", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-74" + ], + "cwe_details": { + "CWE-74": { + "name": "Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')", + "description": "The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component." + } + } + } + ], + "summary": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", + "severity": "Critical", + "components": { + "npm://ejs:3.1.6": { + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://ejs:3.1.6" + } + ] + ] + } + }, + "issue_id": "XRAY-520200", + "extended_information": { + "short_description": "Insufficient input validation can lead to template injection in ejs when attackers can control both the rendered template and rendering options.", + "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to bypass ejs' template injection restrictions, by abusing the `closeDelimiter` rendering option, in the case when -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\n\nThe vulnerability was **rightfully disputed** due to the fact that a vulnerable configuration is extremely unlikely to exist in any real-world setup. As such, the maintainers will not provide a fix for this (non-)issue.\n\nExample of a vulnerable application -\n```js\nconst express = require('express')\nconst app = express()\nconst port = 3000\n\napp.set('view engine', 'ejs');\n\napp.get('/page', (req,res) =\u003e {\n res.render('page', req.query); // OPTS (2nd parameter) IS ATTACKER-CONTROLLED\n})\n\napp.listen(port, () =\u003e {\n console.log(\"Example app listening on port ${port}\")\n})\n```\n\nContents of `page.ejs` (very unlikely to be attacker controlled) -\n```js\n%%1\");process.mainModule.require('child_process').execSync('calc');//\n```\n\nIn this case, sending `closeDelimiter` with the same malicious code that already exists at `page.ejs` will trigger the injection -\n`http://127.0.0.1:3000/page?settings[view%20options][closeDelimiter]=1\")%3bprocess.mainModule.require('child_process').execSync('calc')%3b//`", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS does not take into account the rarity of a vulnerable configuration to exist", + "is_positive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The vulnerability can be exploited only under the following conditions -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\nThis vulnerable configuration is extremely unlikely to exist in any real-world setup.", + "is_positive": true + }, + { + "name": "The issue has been disputed by the vendor", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "Published exploit demonstrates template injection" + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2022-29078", + "cvss_v2_score": "7.5", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-94", + "CWE-74" + ], + "cwe_details": { + "CWE-74": { + "name": "Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')", + "description": "The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component." + }, + "CWE-94": { + "name": "Improper Control of Generation of Code ('Code Injection')", + "description": "The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "23" + } + ] + } + } + } + ], + "summary": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", + "severity": "Critical", + "components": { + "npm://ejs:3.1.6": { + "fixed_versions": [ + "[3.1.7]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://ejs:3.1.6" + } + ] + ] + } + }, + "issue_id": "XRAY-209002", + "extended_information": { + "short_description": "Insufficient input validation in EJS enables attackers to perform template injection when attacker can control the rendering options.", + "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to perform template injection on the `opts.outputFunctionName` variable, since the variable is injected into the template body without any escaping. Although it is unlikely that the attacker can directly control the `outputFunctionName` property, it is possible that it can be influenced in conjunction with a prototype pollution vulnerability.\n\nOnce template injection is achieved, the attacker can immediately perform remote code execution since the template engine (EJS) allows executing arbitrary JavaScript code.\n\nExample of a vulnerable Node.js application -\n```js\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst lodash = require('lodash');\nconst ejs = require('ejs');\n\nconst app = express();\n\napp\n .use(bodyParser.urlencoded({extended: true}))\n .use(bodyParser.json());\n\napp.set('views', './');\napp.set('view engine', 'ejs');\n\napp.get(\"/\", (req, res) =\u003e {\n res.render('index');\n});\n\napp.post(\"/\", (req, res) =\u003e {\n let data = {};\n let input = JSON.parse(req.body.content);\n lodash.defaultsDeep(data, input);\n res.json({message: \"OK\"});\n});\n\nlet server = app.listen(8086, '0.0.0.0', function() {\n console.log('Listening on port %d', server.address().port);\n});\n```\n\nExploiting the above example for RCE -\n`curl 127.0.0.1:8086 -v --data 'content={\"constructor\": {\"prototype\": {\"outputFunctionName\": \"a; return global.process.mainModule.constructor._load(\\\"child_process\\\").execSync(\\\"whoami\\\"); //\"}}}'\n`\n\nDue to the prototype pollution in the `lodash.defaultsDeep` call, an attacker can inject the `outputFunctionName` property with an arbitrary value. The chosen value executes an arbitrary process via the `child_process` module.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker has to find a way to get their malicious input to `opts.outputFunctionName`, which will usually require exploitation of a prototype pollution vulnerability somewhere else in the code. However, there could be cases where the attacker can pass malicious data to the render function directly because of design problems in other code using EJS.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "There are multiple examples of exploits for this vulnerability online." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Successful exploitation of this vulnerability leads to remote code execution." + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\nNote that this mitigation is supposed to stop any prototype pollution attacks which can allow an attacker to control the `opts.outputFunctionName` parameter indirectly.\n\nThe mitigation will not stop any (extremely unlikely) scenarios where the JavaScript code allows external input to directly affect `opts.outputFunctionName`." + } + } + ], + "component_id": "root", + "package_type": "generic", + "status": "completed" + } + ] + }, + "jas_scans": { + "contextual_analysis": [ + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Applicability Scanner", + "rules": [ + { + "id": "applic_CVE-2018-16487", + "name": "CVE-2018-16487", + "shortDescription": { + "text": "Scanner for CVE-2018-16487" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": 6.9 + } + }, + { + "id": "applic_CVE-2019-10744", + "name": "CVE-2019-10744", + "shortDescription": { + "text": "Scanner for CVE-2019-10744" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": 6.9 + } + }, + { + "id": "applic_CVE-2020-28500", + "name": "CVE-2020-28500", + "shortDescription": { + "text": "Scanner for CVE-2020-28500" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument.", + "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": 6.9 + } + }, + { + "id": "applic_CVE-2020-8203", + "name": "CVE-2020-8203", + "shortDescription": { + "text": "Scanner for CVE-2020-8203" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": 6.9 + } + }, + { + "id": "applic_CVE-2021-23337", + "name": "CVE-2021-23337", + "shortDescription": { + "text": "Scanner for CVE-2021-23337" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument.", + "markdown": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": 6.9 + } + }, + { + "id": "applic_CVE-2022-29078", + "name": "CVE-2022-29078", + "shortDescription": { + "text": "Scanner for CVE-2022-29078" + }, + "fullDescription": { + "text": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": 6.9 + } + }, + { + "id": "applic_CVE-2024-33883", + "name": "CVE-2024-33883", + "shortDescription": { + "text": "Scanner for CVE-2024-33883" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `ejs.compile()` is called.", + "markdown": "The scanner checks whether the vulnerable function `ejs.compile()` is called." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": 6.9 + } + }, + { + "id": "applic_CVE-2023-29827", + "name": "CVE-2023-29827", + "shortDescription": { + "text": "Scanner for CVE-2023-29827" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`", + "markdown": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": 6.9 + } + }, + { + "id": "applic_CVE-2019-1010266", + "name": "CVE-2019-1010266", + "shortDescription": { + "text": "Scanner for uncovered CVE-2019-1010266" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2018-3721", + "name": "CVE-2018-3721", + "shortDescription": { + "text": "Scanner for uncovered CVE-2018-3721" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-29041", + "name": "CVE-2024-29041", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-29041" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-39249", + "name": "CVE-2024-39249", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-39249" + }, + "fullDescription": { + "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", + "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + }, + "properties": { + "applicability": "not_covered", + "security-severity": 6.9 + } + }, + { + "id": "applic_CVE-2024-39249", + "name": "CVE-2024-39249", + "shortDescription": { + "text": "Scanner for indirect dependency CVE-2024-39249" + }, + "fullDescription": { + "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", + "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + }, + "properties": { + "applicability": "not_applicable" + } + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720701347-1703878693/Applicability_1720701359/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [ + { + "ruleId": "applic_CVE-2018-16487", + "message": { + "text": "Prototype pollution `Object.freeze` remediation was detected" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 1, + "startColumn": 0, + "endLine": 1, + "endColumn": 31, + "snippet": { + "text": "Object.freeze(Object.prototype)" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2018-16487", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + } + }, + { + "ruleId": "applic_CVE-2019-10744", + "message": { + "text": "Prototype pollution `Object.freeze` remediation was detected" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 1, + "startColumn": 0, + "endLine": 1, + "endColumn": 31, + "snippet": { + "text": "Object.freeze(Object.prototype)" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2019-10744", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." + } + }, + { + "ruleId": "applic_CVE-2020-28500", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." + } + }, + { + "ruleId": "applic_CVE-2020-8203", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." + } + }, + { + "ruleId": "applic_CVE-2021-23337", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." + } + }, + { + "ruleId": "applic_CVE-2022-29078", + "message": { + "text": "Prototype pollution `Object.freeze` remediation was detected" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 1, + "startColumn": 0, + "endLine": 1, + "endColumn": 31, + "snippet": { + "text": "Object.freeze(Object.prototype)" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2022-29078", + "kind": "pass", + "message": { + "text": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + } + }, + { + "ruleId": "applic_CVE-2024-33883", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `ejs.compile()` is called." + } + }, + { + "ruleId": "applic_CVE-2023-29827", + "message": { + "text": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 15, + "startColumn": 0, + "endLine": 15, + "endColumn": 29, + "snippet": { + "text": "app.set('view engine', 'ejs')" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2023-29827", + "message": { + "text": "The vulnerable function render is called" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 27, + "startColumn": 2, + "endLine": 27, + "endColumn": 37, + "snippet": { + "text": "res.render('pages/index',req.query)" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2024-39249", + "kind": "pass", + "message": { + "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + } + } + ] + } + ], + "secrets": [ + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Secrets scanner", + "rules": [ + { + "id": "REQ.SECRET.GENERIC.TEXT", + "name": "REQ.SECRET.GENERIC.TEXT", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.TEXT" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.GENERIC.CODE", + "name": "REQ.SECRET.GENERIC.CODE", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.CODE" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.GENERIC.URL", + "name": "REQ.SECRET.GENERIC.URL", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.URL" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.KEYS", + "name": "REQ.SECRET.KEYS", + "shortDescription": { + "text": "Scanner for REQ.SECRET.KEYS" + }, + "fullDescription": { + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": 6.9 + } + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720701347-1703878693/Secrets_1720701347/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [ + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + }, + "region": { + "startLine": 1, + "startColumn": 0, + "endLine": 1, + "endColumn": 0, + "snippet": { + "text": "AKI************" + } + } + } + } + ] + }, + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + }, + "region": { + "startLine": 2, + "startColumn": 0, + "endLine": 2, + "endColumn": 0, + "snippet": { + "text": "Sqc************" + } + } + } + } + ] + }, + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + }, + "region": { + "startLine": 3, + "startColumn": 0, + "endLine": 3, + "endColumn": 0, + "snippet": { + "text": "gho************" + } + } + } + } + ] + }, + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 11, + "startColumn": 15, + "endLine": 11, + "endColumn": 15, + "snippet": { + "text": "AKI************" + } + } + } + } + ] + }, + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 12, + "startColumn": 12, + "endLine": 12, + "endColumn": 12, + "snippet": { + "text": "\"Sq************" + } + } + } + } + ] + } + ] + } + ], + "iac": [ + { + "tool": { + "driver": { + "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/infrastructure-as-code-iac", + "name": "JFrog Terraform scanner", + "rules": [], + "version": "1.8.3" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/assafa/.jfrog/dependencies/analyzerManager/iac_scanner/tf_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720701347-1703878693/IaC_1720701359/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [] + } + ], + "sast": [ + { + "tool": { + "driver": { + "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sast", + "name": "USAF", + "rules": [ + { + "id": "js-express-without-helmet", + "shortDescription": { + "text": "Express Not Using Helmet" + }, + "fullDescription": { + "text": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n", + "markdown": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n" + }, + "properties": { + "security-severity": 3.9 + } + }, + { + "id": "js-insecure-random", + "shortDescription": { + "text": "Use of Insecure Random" + }, + "fullDescription": { + "text": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n", + "markdown": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" + }, + "defaultConfiguration": { + "parameters": { + "properties": { + "CWE": "338" + } + } + }, + "properties": { + "security-severity": 3.9 + } + }, + { + "id": "js-template-injection", + "shortDescription": { + "text": "Template Object Injection" + }, + "fullDescription": { + "text": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n", + "markdown": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n" + }, + "defaultConfiguration": { + "parameters": { + "properties": { + "CWE": "73" + } + } + }, + "properties": { + "security-severity": 8.9 + } + } + ], + "version": "1.8.3" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/assafa/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720701347-1703878693/Sast_1720701360/results.sarif", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720701347-1703878693/Sast_1720701360/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [ + { + "ruleId": "js-insecure-random", + "level": "note", + "message": { + "text": "Use of Insecure Random" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" + }, + "region": { + "startLine": 136, + "startColumn": 22, + "endLine": 136, + "endColumn": 35, + "snippet": { + "text": "Math.random()" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "public.js.bootstrap.^_0.Util.getUID" + } + ] + } + ] + }, + { + "ruleId": "js-insecure-random", + "level": "note", + "message": { + "text": "Use of Insecure Random" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + }, + "region": { + "startLine": 135, + "startColumn": 22, + "endLine": 135, + "endColumn": 35, + "snippet": { + "text": "Math.random()" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "public.js.bootstrap\u003cdot\u003ebundle.^_0.Util.getUID" + } + ] + } + ] + }, + { + "ruleId": "js-express-without-helmet", + "level": "note", + "message": { + "text": "Express Not Using Helmet" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 9, + "startColumn": 11, + "endLine": 9, + "endColumn": 20, + "snippet": { + "text": "express()" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server" + } + ] + } + ] + }, + { + "ruleId": "js-template-injection", + "level": "error", + "message": { + "text": "Template Object Injection" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 27, + "startColumn": 28, + "endLine": 27, + "endColumn": 37, + "snippet": { + "text": "req.query" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 22, + "startColumn": 23, + "endLine": 22, + "endColumn": 26, + "snippet": { + "text": "req" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 27, + "startColumn": 28, + "endLine": 27, + "endColumn": 31, + "snippet": { + "text": "req" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 27, + "startColumn": 28, + "endLine": 27, + "endColumn": 37, + "snippet": { + "text": "req.query" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + } + ] + } + ] + } + ] + } + ] + } + ] + } + } + ] + } \ No newline at end of file diff --git a/tests/testdata/other/output/formats/audit_sarif.json b/tests/testdata/other/output/formats/audit_sarif.json new file mode 100644 index 00000000..a7879001 --- /dev/null +++ b/tests/testdata/other/output/formats/audit_sarif.json @@ -0,0 +1,1291 @@ +{ + "version": "2.1.0", + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "runs": [ + { + "tool": { + "driver": { + "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sca", + "name": "JFrog Xray SCA", + "rules": [ + { + "id": "CVE-2023-29827_ejs_3.1.6", + "shortDescription": { + "text": "[CVE-2023-29827] ejs 3.1.6" + }, + "help": { + "text": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Applicable | `ejs 3.1.6` | No fix available |" + }, + "properties": { + "security-severity": "9.8" + } + }, + { + "id": "CVE-2018-3721_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2018-3721] lodash 4.17.0" + }, + "help": { + "text": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.5] |" + }, + "properties": { + "security-severity": "6.5" + } + }, + { + "id": "CVE-2024-29041_express_4.18.2", + "shortDescription": { + "text": "[CVE-2024-29041] express 4.18.2" + }, + "help": { + "text": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.1 | Not Covered | `express 4.18.2` | [4.19.2], [5.0.0-beta.3] |" + }, + "properties": { + "security-severity": "6.1" + } + }, + { + "id": "CVE-2019-1010266_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2019-1010266] lodash 4.17.0" + }, + "help": { + "text": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.11] |" + }, + "properties": { + "security-severity": "6.5" + } + }, + { + "id": "CVE-2024-39249_async_3.2.4", + "shortDescription": { + "text": "[CVE-2024-39249] async 3.2.4" + }, + "help": { + "text": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Not Covered | `ejs 3.1.6` | No fix available |" + }, + "properties": { + "security-severity": "0.0" + } + }, + { + "id": "CVE-2022-29078_ejs_3.1.6", + "shortDescription": { + "text": "[CVE-2022-29078] ejs 3.1.6" + }, + "help": { + "text": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Not Applicable | `ejs 3.1.6` | [3.1.7] |" + }, + "properties": { + "security-severity": "9.8" + } + }, + { + "id": "CVE-2019-10744_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2019-10744] lodash 4.17.0" + }, + "help": { + "text": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.1 | Not Applicable | `lodash 4.17.0` | [4.17.12] |" + }, + "properties": { + "security-severity": "9.1" + } + }, + { + "id": "CVE-2021-23337_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2021-23337] lodash 4.17.0" + }, + "help": { + "text": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.2 | Not Applicable | `lodash 4.17.0` | [4.17.21] |" + }, + "properties": { + "security-severity": "7.2" + } + }, + { + "id": "CVE-2020-8203_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2020-8203] lodash 4.17.0" + }, + "help": { + "text": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.4 | Not Applicable | `lodash 4.17.0` | [4.17.19] |" + }, + "properties": { + "security-severity": "7.4" + } + }, + { + "id": "CVE-2024-33883_ejs_3.1.6", + "shortDescription": { + "text": "[CVE-2024-33883] ejs 3.1.6" + }, + "help": { + "text": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Not Applicable | `ejs 3.1.6` | [3.1.10] |" + }, + "properties": { + "security-severity": "0.0" + } + }, + { + "id": "CVE-2018-16487_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2018-16487] lodash 4.17.0" + }, + "help": { + "text": "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.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.6 | Not Applicable | `lodash 4.17.0` | [4.17.11] |" + }, + "properties": { + "security-severity": "5.6" + } + }, + { + "id": "CVE-2020-28500_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2020-28500] lodash 4.17.0" + }, + "help": { + "text": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.3 | Not Applicable | `lodash 4.17.0` | [4.17.21] |" + }, + "properties": { + "security-severity": "5.3" + } + } + ], + "version": "3.98.2" + } + }, + "results": [ + { + "ruleId": "CVE-2023-29827_ejs_3.1.6", + "ruleIndex": 0, + "level": "error", + "message": { + "text": "[CVE-2023-29827] ejs 3.1.6" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file://package.json" + } + } + } + ] + }, + { + "ruleId": "CVE-2018-3721_lodash_4.17.0", + "ruleIndex": 1, + "level": "warning", + "message": { + "text": "[CVE-2018-3721] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file://package.json" + } + } + } + ] + }, + { + "ruleId": "CVE-2024-29041_express_4.18.2", + "ruleIndex": 2, + "level": "warning", + "message": { + "text": "[CVE-2024-29041] express 4.18.2" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file://package.json" + } + } + } + ] + }, + { + "ruleId": "CVE-2019-1010266_lodash_4.17.0", + "ruleIndex": 3, + "level": "warning", + "message": { + "text": "[CVE-2019-1010266] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file://package.json" + } + } + } + ] + }, + { + "ruleId": "CVE-2024-39249_async_3.2.4", + "ruleIndex": 4, + "level": "none", + "message": { + "text": "[CVE-2024-39249] ejs 3.1.6" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file://package.json" + } + } + } + ] + }, + { + "ruleId": "CVE-2022-29078_ejs_3.1.6", + "ruleIndex": 5, + "level": "error", + "message": { + "text": "[CVE-2022-29078] ejs 3.1.6" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file://package.json" + } + } + } + ] + }, + { + "ruleId": "CVE-2019-10744_lodash_4.17.0", + "ruleIndex": 6, + "level": "error", + "message": { + "text": "[CVE-2019-10744] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file://package.json" + } + } + } + ] + }, + { + "ruleId": "CVE-2021-23337_lodash_4.17.0", + "ruleIndex": 7, + "level": "error", + "message": { + "text": "[CVE-2021-23337] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file://package.json" + } + } + } + ] + }, + { + "ruleId": "CVE-2020-8203_lodash_4.17.0", + "ruleIndex": 8, + "level": "error", + "message": { + "text": "[CVE-2020-8203] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file://package.json" + } + } + } + ] + }, + { + "ruleId": "CVE-2024-33883_ejs_3.1.6", + "ruleIndex": 9, + "level": "warning", + "message": { + "text": "[CVE-2024-33883] ejs 3.1.6" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file://package.json" + } + } + } + ] + }, + { + "ruleId": "CVE-2018-16487_lodash_4.17.0", + "ruleIndex": 10, + "level": "warning", + "message": { + "text": "[CVE-2018-16487] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file://package.json" + } + } + } + ] + }, + { + "ruleId": "CVE-2020-28500_lodash_4.17.0", + "ruleIndex": 11, + "level": "warning", + "message": { + "text": "[CVE-2020-28500] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file://package.json" + } + } + } + ] + } + ] + }, + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Applicability Scanner", + "rules": [ + { + "id": "applic_CVE-2018-16487", + "name": "CVE-2018-16487", + "shortDescription": { + "text": "Scanner for CVE-2018-16487" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2019-10744", + "name": "CVE-2019-10744", + "shortDescription": { + "text": "Scanner for CVE-2019-10744" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2020-28500", + "name": "CVE-2020-28500", + "shortDescription": { + "text": "Scanner for CVE-2020-28500" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument.", + "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2020-8203", + "name": "CVE-2020-8203", + "shortDescription": { + "text": "Scanner for CVE-2020-8203" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2021-23337", + "name": "CVE-2021-23337", + "shortDescription": { + "text": "Scanner for CVE-2021-23337" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument.", + "markdown": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2022-29078", + "name": "CVE-2022-29078", + "shortDescription": { + "text": "Scanner for CVE-2022-29078" + }, + "fullDescription": { + "text": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-33883", + "name": "CVE-2024-33883", + "shortDescription": { + "text": "Scanner for CVE-2024-33883" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `ejs.compile()` is called.", + "markdown": "The scanner checks whether the vulnerable function `ejs.compile()` is called." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-29827", + "name": "CVE-2023-29827", + "shortDescription": { + "text": "Scanner for CVE-2023-29827" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`", + "markdown": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2018-3721", + "name": "CVE-2018-3721", + "shortDescription": { + "text": "Scanner for uncovered CVE-2018-3721" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2019-1010266", + "name": "CVE-2019-1010266", + "shortDescription": { + "text": "Scanner for uncovered CVE-2019-1010266" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-29041", + "name": "CVE-2024-29041", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-29041" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-39249", + "name": "CVE-2024-39249", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-39249" + }, + "fullDescription": { + "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", + "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + }, + "properties": { + "applicability": "not_covered", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-39249", + "name": "CVE-2024-39249", + "shortDescription": { + "text": "Scanner for indirect dependency CVE-2024-39249" + }, + "fullDescription": { + "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", + "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + }, + "properties": { + "applicability": "not_applicable" + } + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720708975-4044569217/Applicability_1720708983/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [ + { + "ruleId": "applic_CVE-2018-16487", + "message": { + "text": "Prototype pollution `Object.freeze` remediation was detected" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 1, + "startColumn": 0, + "endLine": 1, + "endColumn": 31, + "snippet": { + "text": "Object.freeze(Object.prototype)" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2018-16487", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + } + }, + { + "ruleId": "applic_CVE-2019-10744", + "message": { + "text": "Prototype pollution `Object.freeze` remediation was detected" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 1, + "startColumn": 0, + "endLine": 1, + "endColumn": 31, + "snippet": { + "text": "Object.freeze(Object.prototype)" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2019-10744", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." + } + }, + { + "ruleId": "applic_CVE-2020-28500", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." + } + }, + { + "ruleId": "applic_CVE-2020-8203", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." + } + }, + { + "ruleId": "applic_CVE-2021-23337", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." + } + }, + { + "ruleId": "applic_CVE-2022-29078", + "message": { + "text": "Prototype pollution `Object.freeze` remediation was detected" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 1, + "startColumn": 0, + "endLine": 1, + "endColumn": 31, + "snippet": { + "text": "Object.freeze(Object.prototype)" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2022-29078", + "kind": "pass", + "message": { + "text": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + } + }, + { + "ruleId": "applic_CVE-2024-33883", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `ejs.compile()` is called." + } + }, + { + "ruleId": "applic_CVE-2023-29827", + "message": { + "text": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 15, + "startColumn": 0, + "endLine": 15, + "endColumn": 29, + "snippet": { + "text": "app.set('view engine', 'ejs')" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2023-29827", + "message": { + "text": "The vulnerable function render is called" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 27, + "startColumn": 2, + "endLine": 27, + "endColumn": 37, + "snippet": { + "text": "res.render('pages/index',req.query)" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2024-39249", + "kind": "pass", + "message": { + "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + } + } + ] + }, + { + "tool": { + "driver": { + "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/infrastructure-as-code-iac", + "name": "JFrog Terraform scanner", + "rules": [], + "version": "1.8.3" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/assafa/.jfrog/dependencies/analyzerManager/iac_scanner/tf_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720708975-4044569217/IaC_1720708975/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [] + }, + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Secrets scanner", + "rules": [ + { + "id": "REQ.SECRET.GENERIC.TEXT", + "name": "REQ.SECRET.GENERIC.TEXT", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.TEXT" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.GENERIC.CODE", + "name": "REQ.SECRET.GENERIC.CODE", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.CODE" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.GENERIC.URL", + "name": "REQ.SECRET.GENERIC.URL", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.URL" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.KEYS", + "name": "REQ.SECRET.KEYS", + "shortDescription": { + "text": "Scanner for REQ.SECRET.KEYS" + }, + "fullDescription": { + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720708975-4044569217/Secrets_1720708975/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [ + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + }, + "region": { + "startLine": 1, + "startColumn": 0, + "endLine": 1, + "endColumn": 0, + "snippet": { + "text": "AKI************" + } + } + } + } + ] + }, + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + }, + "region": { + "startLine": 2, + "startColumn": 0, + "endLine": 2, + "endColumn": 0, + "snippet": { + "text": "Sqc************" + } + } + } + } + ] + }, + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + }, + "region": { + "startLine": 3, + "startColumn": 0, + "endLine": 3, + "endColumn": 0, + "snippet": { + "text": "gho************" + } + } + } + } + ] + }, + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 11, + "startColumn": 15, + "endLine": 11, + "endColumn": 15, + "snippet": { + "text": "AKI************" + } + } + } + } + ] + }, + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 12, + "startColumn": 12, + "endLine": 12, + "endColumn": 12, + "snippet": { + "text": "\"Sq************" + } + } + } + } + ] + } + ] + }, + { + "tool": { + "driver": { + "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sast", + "name": "USAF", + "rules": [ + { + "id": "js-express-without-helmet", + "shortDescription": { + "text": "Express Not Using Helmet" + }, + "fullDescription": { + "text": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n", + "markdown": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n" + }, + "properties": { + "security-severity": "3.9" + } + }, + { + "id": "js-insecure-random", + "shortDescription": { + "text": "Use of Insecure Random" + }, + "fullDescription": { + "text": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n", + "markdown": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" + }, + "defaultConfiguration": { + "parameters": { + "properties": { + "CWE": "338" + } + } + }, + "properties": { + "security-severity": "3.9" + } + }, + { + "id": "js-template-injection", + "shortDescription": { + "text": "Template Object Injection" + }, + "fullDescription": { + "text": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n", + "markdown": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n" + }, + "defaultConfiguration": { + "parameters": { + "properties": { + "CWE": "73" + } + } + }, + "properties": { + "security-severity": "8.9" + } + } + ], + "version": "1.8.3" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/assafa/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720708975-4044569217/Sast_1720708982/results.sarif", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720708975-4044569217/Sast_1720708982/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [ + { + "ruleId": "js-insecure-random", + "level": "note", + "message": { + "text": "Use of Insecure Random" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" + }, + "region": { + "startLine": 136, + "startColumn": 22, + "endLine": 136, + "endColumn": 35, + "snippet": { + "text": "Math.random()" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "public.js.bootstrap.^_0.Util.getUID" + } + ] + } + ] + }, + { + "ruleId": "js-insecure-random", + "level": "note", + "message": { + "text": "Use of Insecure Random" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + }, + "region": { + "startLine": 135, + "startColumn": 22, + "endLine": 135, + "endColumn": 35, + "snippet": { + "text": "Math.random()" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "public.js.bootstrap\u003cdot\u003ebundle.^_0.Util.getUID" + } + ] + } + ] + }, + { + "ruleId": "js-express-without-helmet", + "level": "note", + "message": { + "text": "Express Not Using Helmet" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 9, + "startColumn": 11, + "endLine": 9, + "endColumn": 20, + "snippet": { + "text": "express()" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server" + } + ] + } + ] + }, + { + "ruleId": "js-template-injection", + "level": "error", + "message": { + "text": "Template Object Injection" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 27, + "startColumn": 28, + "endLine": 27, + "endColumn": 37, + "snippet": { + "text": "req.query" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 22, + "startColumn": 23, + "endLine": 22, + "endColumn": 26, + "snippet": { + "text": "req" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 27, + "startColumn": 28, + "endLine": 27, + "endColumn": 31, + "snippet": { + "text": "req" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 27, + "startColumn": 28, + "endLine": 27, + "endColumn": 37, + "snippet": { + "text": "req.query" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + } + ] + } + ] + } + ] + } + ] + } + ] + } + \ No newline at end of file diff --git a/tests/testdata/other/output/formats/audit_simple_json.json b/tests/testdata/other/output/formats/audit_simple_json.json new file mode 100644 index 00000000..962e80a7 --- /dev/null +++ b/tests/testdata/other/output/formats/audit_simple_json.json @@ -0,0 +1,883 @@ +{ + "vulnerabilities": [ + { + "severity": "Critical", + "impactedPackageName": "ejs", + "impactedPackageVersion": "3.1.6", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6" + } + ], + "summary": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", + "applicable": "Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2023-29827", + "cvssV2": "", + "cvssV3": "9.8", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`", + "evidence": [ + { + "file": "server.js", + "startLine": 15, + "endLine": 15, + "endColumn": 29, + "snippet": "app.set('view engine', 'ejs')", + "reason": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" + } + ] + } + } + ], + "issueId": "XRAY-520200", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "ejs", + "version": "3.1.6" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Low", + "summary": "Insufficient input validation can lead to template injection in ejs when attackers can control both the rendered template and rendering options.", + "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to bypass ejs' template injection restrictions, by abusing the `closeDelimiter` rendering option, in the case when -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\n\nThe vulnerability was **rightfully disputed** due to the fact that a vulnerable configuration is extremely unlikely to exist in any real-world setup. As such, the maintainers will not provide a fix for this (non-)issue.\n\nExample of a vulnerable application -\n```js\nconst express = require('express')\nconst app = express()\nconst port = 3000\n\napp.set('view engine', 'ejs');\n\napp.get('/page', (req,res) =\u003e {\n res.render('page', req.query); // OPTS (2nd parameter) IS ATTACKER-CONTROLLED\n})\n\napp.listen(port, () =\u003e {\n console.log(\"Example app listening on port ${port}\")\n})\n```\n\nContents of `page.ejs` (very unlikely to be attacker controlled) -\n```js\n%%1\");process.mainModule.require('child_process').execSync('calc');//\n```\n\nIn this case, sending `closeDelimiter` with the same malicious code that already exists at `page.ejs` will trigger the injection -\n`http://127.0.0.1:3000/page?settings[view%20options][closeDelimiter]=1\")%3bprocess.mainModule.require('child_process').execSync('calc')%3b//`", + "severityReasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS does not take into account the rarity of a vulnerable configuration to exist", + "isPositive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The vulnerability can be exploited only under the following conditions -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\nThis vulnerable configuration is extremely unlikely to exist in any real-world setup.", + "isPositive": true + }, + { + "name": "The issue has been disputed by the vendor", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "Published exploit demonstrates template injection" + } + ] + } + }, + { + "severity": "Medium", + "impactedPackageName": "express", + "impactedPackageVersion": "4.18.2", + "impactedPackageType": "npm", + "components": [ + { + "name": "express", + "version": "4.18.2" + } + ], + "summary": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", + "applicable": "Not Covered", + "fixedVersions": [ + "[4.19.2]", + "[5.0.0-beta.3]" + ], + "cves": [ + { + "id": "CVE-2024-29041", + "cvssV2": "", + "cvssV3": "6.1", + "applicability": { + "status": "Not Covered" + } + } + ], + "issueId": "XRAY-594935", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "express", + "version": "4.18.2" + } + ] + ], + "jfrogResearchInformation": { + "severity": "" + } + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0" + } + ], + "summary": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", + "applicable": "Not Covered", + "fixedVersions": [ + "[4.17.5]" + ], + "cves": [ + { + "id": "CVE-2018-3721", + "cvssV2": "4.0", + "cvssV3": "6.5", + "applicability": { + "status": "Not Covered" + } + } + ], + "issueId": "XRAY-72918", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "" + } + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0" + } + ], + "summary": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", + "applicable": "Not Covered", + "fixedVersions": [ + "[4.17.11]" + ], + "cves": [ + { + "id": "CVE-2019-1010266", + "cvssV2": "4.0", + "cvssV3": "6.5", + "applicability": { + "status": "Not Covered" + } + } + ], + "issueId": "XRAY-85049", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "" + } + }, + { + "severity": "Unknown", + "impactedPackageName": "async", + "impactedPackageVersion": "3.2.4", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6" + } + ], + "summary": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", + "applicable": "Not Covered", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-39249", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Not Covered", + "scannerDescription": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + } + } + ], + "issueId": "XRAY-609848", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "ejs", + "version": "3.1.6" + }, + { + "name": "jake", + "version": "10.8.7" + }, + { + "name": "async", + "version": "3.2.4" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Low", + "summary": "ReDoS in Async may lead to denial of service while parsing malformed source code.", + "severityReasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The reported CVSS does not reflect the severity of the vulnerability.", + "isPositive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "To exploit this issue an attacker must change the source code of the application. In cases where an attacker can already modify (or fully control) the source code, the attacker can immediately achieve arbitrary code execution - thus this issue has almost no security impact.", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "A proof-of-concept has been published in the advisory." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The issue requires the use of the `async.autoInject` function to be vulnerable.", + "isPositive": true + } + ] + } + }, + { + "severity": "Critical", + "impactedPackageName": "ejs", + "impactedPackageVersion": "3.1.6", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6" + } + ], + "summary": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", + "applicable": "Not Applicable", + "fixedVersions": [ + "[3.1.7]" + ], + "cves": [ + { + "id": "CVE-2022-29078", + "cvssV2": "7.5", + "cvssV3": "9.8", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "evidence": [ + { + "file": "server.js", + "startLine": 1, + "endLine": 1, + "endColumn": 31, + "snippet": "Object.freeze(Object.prototype)", + "reason": "Prototype pollution `Object.freeze` remediation was detected" + } + ] + } + } + ], + "issueId": "XRAY-209002", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "ejs", + "version": "3.1.6" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Insufficient input validation in EJS enables attackers to perform template injection when attacker can control the rendering options.", + "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to perform template injection on the `opts.outputFunctionName` variable, since the variable is injected into the template body without any escaping. Although it is unlikely that the attacker can directly control the `outputFunctionName` property, it is possible that it can be influenced in conjunction with a prototype pollution vulnerability.\n\nOnce template injection is achieved, the attacker can immediately perform remote code execution since the template engine (EJS) allows executing arbitrary JavaScript code.\n\nExample of a vulnerable Node.js application -\n```js\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst lodash = require('lodash');\nconst ejs = require('ejs');\n\nconst app = express();\n\napp\n .use(bodyParser.urlencoded({extended: true}))\n .use(bodyParser.json());\n\napp.set('views', './');\napp.set('view engine', 'ejs');\n\napp.get(\"/\", (req, res) =\u003e {\n res.render('index');\n});\n\napp.post(\"/\", (req, res) =\u003e {\n let data = {};\n let input = JSON.parse(req.body.content);\n lodash.defaultsDeep(data, input);\n res.json({message: \"OK\"});\n});\n\nlet server = app.listen(8086, '0.0.0.0', function() {\n console.log('Listening on port %d', server.address().port);\n});\n```\n\nExploiting the above example for RCE -\n`curl 127.0.0.1:8086 -v --data 'content={\"constructor\": {\"prototype\": {\"outputFunctionName\": \"a; return global.process.mainModule.constructor._load(\\\"child_process\\\").execSync(\\\"whoami\\\"); //\"}}}'\n`\n\nDue to the prototype pollution in the `lodash.defaultsDeep` call, an attacker can inject the `outputFunctionName` property with an arbitrary value. The chosen value executes an arbitrary process via the `child_process` module.", + "severityReasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker has to find a way to get their malicious input to `opts.outputFunctionName`, which will usually require exploitation of a prototype pollution vulnerability somewhere else in the code. However, there could be cases where the attacker can pass malicious data to the render function directly because of design problems in other code using EJS.", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "There are multiple examples of exploits for this vulnerability online." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Successful exploitation of this vulnerability leads to remote code execution." + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\nNote that this mitigation is supposed to stop any prototype pollution attacks which can allow an attacker to control the `opts.outputFunctionName` parameter indirectly.\n\nThe mitigation will not stop any (extremely unlikely) scenarios where the JavaScript code allows external input to directly affect `opts.outputFunctionName`." + } + }, + { + "severity": "Critical", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0" + } + ], + "summary": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.12]" + ], + "cves": [ + { + "id": "CVE-2019-10744", + "cvssV2": "6.4", + "cvssV3": "9.1", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present.", + "evidence": [ + { + "file": "server.js", + "startLine": 1, + "endLine": 1, + "endColumn": 31, + "snippet": "Object.freeze(Object.prototype)", + "reason": "Prototype pollution `Object.freeze` remediation was detected" + } + ] + } + } + ], + "issueId": "XRAY-85679", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "High", + "summary": "Insufficient input validation in lodash defaultsDeep() leads to prototype pollution.", + "details": "[lodash](https://www.npmjs.com/package/lodash) is a modern JavaScript utility library delivering modularity, performance, \u0026 extras.\n\nThe function `defaultsDeep` was found to be vulnerable to prototype pollution, when accepting arbitrary source objects from untrusted input\n\nExample of code vulnerable to this issue - \n```js\nconst lodash = require('lodash'); \nconst evilsrc = {constructor: {prototype: {evilkey: \"evilvalue\"}}};\nlodash.defaultsDeep({}, evilsrc)\n```", + "severityReasons": [ + { + "name": "The issue has an exploit published", + "description": "A public PoC demonstrates exploitation of this issue" + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", + "isPositive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find remote input that propagates into the `defaultsDeep` method (2nd arg)", + "isPositive": true + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." + } + }, + { + "severity": "High", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0" + } + ], + "summary": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.21]" + ], + "cves": [ + { + "id": "CVE-2021-23337", + "cvssV2": "6.5", + "cvssV3": "7.2", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." + } + } + ], + "issueId": "XRAY-140575", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Improper sanitization in the lodash template function leads to JavaScript code injection through the options argument.", + "details": "JavaScript-based applications (both frontend and backend) that use the [template function](https://lodash.com/docs/4.17.15#template) -`_.template([string=''], [options={}])` from the [lodash](https://lodash.com/) utility library and provide the `options` argument (specifically the `variable` option) from untrusted user input, are vulnerable to JavaScript code injection. This issue can be easily exploited, and an exploitation example is [publicly available](https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c#diff-a561630bb56b82342bc66697aee2ad96efddcbc9d150665abd6fb7ecb7c0ab2fR22303) in the fix tests that was introduced in version 4.17.21 - \n```js\nlodash.template('', { variable: '){console.log(process.env)}; with(obj' })()\n```", + "severityReasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "It is highly unlikely that a JS program will accept arbitrary remote input into the template's `options` argument", + "isPositive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must find remote input that propagates into the `options` argument of a `template` call", + "isPositive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Leads to remote code execution through JS code injection" + }, + { + "name": "The issue has an exploit published", + "description": "Published exploit demonstrates arbitrary JS code execution" + } + ] + } + }, + { + "severity": "High", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0" + } + ], + "summary": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.19]" + ], + "cves": [ + { + "id": "CVE-2020-8203", + "cvssV2": "5.8", + "cvssV3": "7.4", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." + } + } + ], + "issueId": "XRAY-114089", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Critical", + "summary": "Prototype pollution in lodash object merging and zipping functions leads to code injection.", + "details": "[lodash](https://lodash.com/) is a JavaScript library which provides utility functions for common programming tasks.\n\nJavaScript frontend and Node.js-based backend applications that merge or zip objects using the lodash functions `mergeWith`, `merge` and `zipObjectDeep` are vulnerable to [prototype pollution](https://medium.com/node-modules/what-is-prototype-pollution-and-why-is-it-such-a-big-deal-2dd8d89a93c) if one or more of the objects it receives as arguments are obtained from user input. \nAn attacker controlling this input given to the vulnerable functions can inject properties to JavaScript special objects such as [Object.prototype](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes) from which all JavaScript objects inherit properties and methods. Any change on `Object.prototype` properties will then propagate through the prototype chain inheritance to all of the objects in a JavaScript application. This in turn would allow an attacker to add new properties or modify existing properties which will have application specific implications that could lead to DoS (denial of service), authentication bypass, privilege escalation and even RCE (remote code execution) in [some cases](https://youtu.be/LUsiFV3dsK8?t=1152). \nAs an example for privilege escalation, consider a JavaScript application that has a `user` object which has a Boolean property of `user.isAdmin` which is used to decide which actions the user may take. If an attacker can modify or add the `isAdmin` property through prototype pollution, it can escalate the privileges of its own user to those of an admin. \nAs exploitation is usually application specific, successful exploitation is much more likely if an attacker have access to the JavaScript application code. As such, frontend applications are more vulnerable to this vulnerability than Node.js backend applications.", + "severityReasons": [ + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "isPositive": true + }, + { + "name": "The issue can be exploited by attackers over the network" + }, + { + "name": "The issue is trivial to exploit and does not require a published writeup or PoC" + } + ], + "remediation": "##### Deployment mitigations\n\nAs general guidelines against prototype pollution, first consider not merging objects originating from user input or using a Map structure instead of an object. If merging objects is needed, look into creating objects without a prototype with `Object.create(null)` or into freezing `Object.prototype` with `Object.freeze()`. Finally, it is always best to perform input validation with a a [JSON schema validator](https://github.com/ajv-validator/ajv), which could mitigate this issue entirely in many cases." + } + }, + { + "severity": "Medium", + "impactedPackageName": "ejs", + "impactedPackageVersion": "3.1.6", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6" + } + ], + "summary": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[3.1.10]" + ], + "cves": [ + { + "id": "CVE-2024-33883", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `ejs.compile()` is called." + } + } + ], + "issueId": "XRAY-599735", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "ejs", + "version": "3.1.6" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Insufficient input validation in EJS may lead to prototype pollution.", + "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as `EJS`, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nA prototype pollution gadget within the EJS template engine could potentially be leveraged by attackers to achieve remote code execution or DoS via prototype pollution.\n\n```\nfunction Template(text, opts) {\n opts = opts || utils.createNullProtoObjWherePossible();\n```\n\nWhen checking for the presence of a property within an object variable, the lookup scope isn't explicitly defined. In JavaScript, the absence of a defined lookup scope prompts a search up to the root prototype (`Object.prototype`). This could potentially be under the control of an attacker if another prototype pollution vulnerability is present within the application.\n\nIf the application server is using the EJS as the backend template engine, and there is another prototype pollution vulnerability in the application, then the attacker could leverage the found gadgets in the EJS template engine to escalate the prototype pollution to remote code execution or DoS.\n\nThe following code will execute a command on the server by polluting `opts.escapeFunction`:\n \n```\nconst express = require('express');\nconst app = express();\nconst port = 8008;\nconst ejs = require('ejs');\n\n// Set EJS as the view engine\napp.set('view engine', 'ejs');\n\napp.get('/', (req, res) =\u003e {\n \n const data = {title: 'Welcome', message: 'Hello'};\n\n // Sample EJS template string\n const templateString = `\u003chtml\u003e\u003chead\u003e\u003ctitle\u003e\u003c%= title %\u003e\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003ch1\u003e\u003c%= message %\u003e\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e`;\n\n const { exec } = require('child_process');\n\n function myFunc() {\n exec('bash -c \"echo 123\"', (error, stdout, stderr) =\u003e {\n if (error) {\n console.error(`exec error: ${error}`);\n return;\n }\n if (stderr){\n console.log(`stderr : ${stderr}`);\n return;\n }\n // Handle success\n console.log(`Command executed successfully. Output: ${stdout}`);\n });\n }\n\n const options = {client:false};\n\n Object.prototype.escapeFunction = myFunc;\n \n const compiledTemplate = ejs.compile(templateString, options);\n const renderedHtml = compiledTemplate(data);\n res.send(renderedHtml);\n});\n\n// Start the server\napp.listen(port, () =\u003e {\n console.log(`Server is running on http://localhost:${port}`);\n});\n```", + "severityReasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "Attackers can only leverage this vulnerability when the application server is using the EJS as the backend template engine. Moreover, there must be a second prototype pollution vulnerability in the application.", + "isPositive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "CVSS does not take into account the unlikely prerequisites necessary for exploitation.", + "isPositive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "A prototype pollution attack allows the attacker to inject new properties into all JavaScript objects.\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable." + } + ] + } + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0" + } + ], + "summary": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.21]" + ], + "cves": [ + { + "id": "CVE-2020-28500", + "cvssV2": "5.0", + "cvssV3": "5.3", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." + } + } + ], + "issueId": "XRAY-140562", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "ReDoS in lodash could lead to a denial of service when handling untrusted strings.", + "details": "JavaScript-based applications that use [lodash](https://github.com/lodash/lodash) and specifically the [_.toNumber](https://lodash.com/docs/4.17.15#toNumber), [_.trim](https://lodash.com/docs/4.17.15#trim) and [_.trimEnd](https://lodash.com/docs/4.17.15#trimEnd) functions, could be vulnerable to DoS (Denial of Service) through a faulty regular expression that introduces a ReDoS (Regular Expression DoS) vulnerability. This vulnerability is only triggered if untrusted user input flows into these vulnerable functions and the attacker can supply arbitrary long strings (over 50kB) that contain whitespaces. \n\nOn a modern Core i7-based system, calling the vulnerable functions with a 50kB string could take between 2 to 3 seconds to execute and 4.5 minutes for a longer 500kB string. The fix improved the regular expression performance so it took only a few milliseconds on the same Core i7-based system. This vulnerability is easily exploitable as all is required is to build a string that triggers it as can be seen in this PoC reproducing code - \n\n```js\nvar untrusted_user_input_50k = \"a\" + ' '.repeat(50000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_50k); // should take a few seconds to run\nvar untrusted_user_input_500k = \"a\" + ' '.repeat(500000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_500k); // should take a few minutes to run\n```", + "severityReasons": [ + { + "name": "The issue has an exploit published", + "description": "Public exploit demonstrated ReDoS" + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "Exploitation depends on parsing user input by the `.toNumber`, `.trim` or `.trimEnd` `lodash` functions, and requires the input to contain whitespaces and be very long (over 50KB)", + "isPositive": true + } + ], + "remediation": "##### Deployment mitigations\n\nTrim untrusted strings based on size before providing it to the vulnerable functions by using the `substring` function to with a fixed maximum size like so - ```js untrusted_user_input.substring(0, max_string_size_less_than_50kB); ```" + } + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0" + } + ], + "summary": "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.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.11]" + ], + "cves": [ + { + "id": "CVE-2018-16487", + "cvssV2": "6.8", + "cvssV3": "5.6", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "evidence": [ + { + "file": "server.js", + "startLine": 1, + "endLine": 1, + "endColumn": 31, + "snippet": "Object.freeze(Object.prototype)", + "reason": "Prototype pollution `Object.freeze` remediation was detected" + } + ] + } + } + ], + "issueId": "XRAY-75300", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "High", + "summary": "Insufficient input validation in the Lodash library leads to prototype pollution.", + "details": "The [Lodash](https://lodash.com/) library is an open-source JavaScript project that simplifies operations on string, arrays, numbers, and other objects. It is widely used in connected devices. \n\nThe `merge`, `mergeWith`, and `defaultsDeep` methods in Lodash are vulnerable to [prototype pollution](https://shieldfy.io/security-wiki/prototype-pollution/introduction-to-prototype-pollution/). Attackers can exploit this vulnerability by specifying a crafted `sources` parameter to any of these methods, which can modify the prototype properties of the `Object`, `Function`, `Array`, `String`, `Number`, and `Boolean` objects. A public [exploit](https://hackerone.com/reports/380873) exists which performs the prototype pollution with an arbitrary key and value.\n\nThe library implementation has a bug in the `safeGet()` function in the `lodash.js` module that allows for adding or modifying `prototype` properties of various objects. The official [solution](https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad) fixes the bug by explicitly forbidding the addition or modification of `prototype` properties.\n\nA related CVE (CVE-2018-3721) covers the same issue prior to Lodash version 4.17.5, but the fix for that was incomplete.", + "severityReasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find remote input that propagates into one of the following methods - \n* `merge` - 2nd argument\n* `mergeWith` - 2nd argument\n* `defaultsDeep` - 2nd argument", + "isPositive": true + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "A public PoC demonstrated exploitation by injecting an attacker controlled key and value into the prototype" + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." + } + } + ], + "securityViolations": null, + "licensesViolations": null, + "licenses": null, + "operationalRiskViolations": null, + "secrets": [ + { + "severity": "Medium", + "file": "fake-creds.txt", + "startLine": 1, + "endLine": 1, + "snippet": "AKI************", + "finding": "Secret keys were found" + }, + { + "severity": "Medium", + "file": "fake-creds.txt", + "startLine": 2, + "endLine": 2, + "snippet": "Sqc************", + "finding": "Secret keys were found" + }, + { + "severity": "Medium", + "file": "fake-creds.txt", + "startLine": 3, + "endLine": 3, + "snippet": "gho************", + "finding": "Secret keys were found" + }, + { + "severity": "Medium", + "file": "server.js", + "startLine": 11, + "startColumn": 15, + "endLine": 11, + "endColumn": 15, + "snippet": "AKI************", + "finding": "Secret keys were found" + }, + { + "severity": "Medium", + "file": "server.js", + "startLine": 12, + "startColumn": 12, + "endLine": 12, + "endColumn": 12, + "snippet": "\"Sq************", + "finding": "Secret keys were found" + } + ], + "iacViolations": null, + "sastViolations": [ + { + "severity": "High", + "file": "server.js", + "startLine": 27, + "startColumn": 28, + "endLine": 27, + "endColumn": 37, + "snippet": "req.query", + "finding": "Template Object Injection", + "scannerDescription": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n", + "codeFlow": [ + [ + { + "file": "server.js", + "startLine": 22, + "startColumn": 23, + "endLine": 22, + "endColumn": 26, + "snippet": "req" + }, + { + "file": "server.js", + "startLine": 27, + "startColumn": 28, + "endLine": 27, + "endColumn": 31, + "snippet": "req" + }, + { + "file": "server.js", + "startLine": 27, + "startColumn": 28, + "endLine": 27, + "endColumn": 37, + "snippet": "req.query" + } + ] + ] + }, + { + "severity": "Low", + "file": "server.js", + "startLine": 9, + "startColumn": 11, + "endLine": 9, + "endColumn": 20, + "snippet": "express()", + "finding": "Express Not Using Helmet", + "scannerDescription": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n" + }, + { + "severity": "Low", + "file": "public/js/bootstrap.js", + "startLine": 136, + "startColumn": 22, + "endLine": 136, + "endColumn": 35, + "snippet": "Math.random()", + "finding": "Use of Insecure Random", + "scannerDescription": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" + }, + { + "severity": "Low", + "file": "public/js/bootstrap.bundle.js", + "startLine": 135, + "startColumn": 22, + "endLine": 135, + "endColumn": 35, + "snippet": "Math.random()", + "finding": "Use of Insecure Random", + "scannerDescription": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" + } + ], + "errors": null, + "multiScanId": "7d5e4733-3f93-11ef-8147-e610d09d7daa" + } + \ No newline at end of file diff --git a/tests/testdata/other/output/formats/audit_summary.json b/tests/testdata/other/output/formats/audit_summary.json new file mode 100644 index 00000000..e69de29b diff --git a/tests/testdata/other/output/formats/audit_table.json b/tests/testdata/other/output/formats/audit_table.json new file mode 100644 index 00000000..e69de29b diff --git a/tests/testdata/other/jobSummary/multi_command_job.md b/tests/testdata/other/output/jobSummary/multi_command_job.md similarity index 100% rename from tests/testdata/other/jobSummary/multi_command_job.md rename to tests/testdata/other/output/jobSummary/multi_command_job.md diff --git a/tests/testdata/other/jobSummary/single_issue.md b/tests/testdata/other/output/jobSummary/single_issue.md similarity index 100% rename from tests/testdata/other/jobSummary/single_issue.md rename to tests/testdata/other/output/jobSummary/single_issue.md diff --git a/tests/testdata/other/jobSummary/single_no_issue.md b/tests/testdata/other/output/jobSummary/single_no_issue.md similarity index 100% rename from tests/testdata/other/jobSummary/single_no_issue.md rename to tests/testdata/other/output/jobSummary/single_no_issue.md diff --git a/tests/utils/test_config.go b/tests/utils/test_config.go index fcf1e6c7..be583877 100644 --- a/tests/utils/test_config.go +++ b/tests/utils/test_config.go @@ -10,7 +10,6 @@ import ( "github.com/stretchr/testify/assert" - "github.com/jfrog/jfrog-cli-security/cli" configTests "github.com/jfrog/jfrog-cli-security/tests" "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/repository" @@ -48,9 +47,7 @@ func CreateJfrogHomeConfig(t *testing.T, encryptPassword bool) { assert.NoError(t, err) } -func InitTestCliDetails() { - testApplication := cli.GetJfrogCliSecurityApp() - +func InitTestCliDetails(testApplication components.App) { configTests.TestApplication = &testApplication if configTests.PlatformCli == nil { configTests.PlatformCli = GetTestCli(testApplication) diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index 639ee44a..10914e86 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" "strconv" + "strings" "testing" "time" @@ -33,6 +34,29 @@ func InitSecurityTest(t *testing.T, xrayMinVersion string) { ValidateXrayVersion(t, xrayMinVersion) } +func ValidateXrayVersion(t *testing.T, minVersion string) { + xrayVersion, err := getTestsXrayVersion() + if err != nil { + assert.NoError(t, err) + return + } + err = clientUtils.ValidateMinimumVersion(clientUtils.Xray, xrayVersion.GetVersion(), minVersion) + if err != nil { + t.Skip(err) + } +} + +func ValidateXscVersion(t *testing.T, minVersion string) { + xscVersion, err := getTestsXscVersion() + if err != nil { + t.Skip(err) + } + err = clientUtils.ValidateMinimumVersion(clientUtils.Xsc, xscVersion.GetVersion(), minVersion) + if err != nil { + t.Skip(err) + } +} + func InitTestWithMockCommandOrParams(t *testing.T, mockCommands ...func(t *testing.T) components.Command) (mockCli *coreTests.JfrogCli, cleanUp func()) { oldHomeDir := os.Getenv(coreutils.HomeDir) // Create server config to use with the command. @@ -76,12 +100,12 @@ func removeDirs(dirs ...string) { } } -func getXrayVersion() (version.Version, error) { +func getTestsXrayVersion() (version.Version, error) { xrayVersion, err := configTests.XrAuth.GetVersion() return *version.NewVersion(xrayVersion), err } -func getXscVersion() (version.Version, error) { +func getTestsXscVersion() (version.Version, error) { xscVersion, err := configTests.XscAuth.GetVersion() return *version.NewVersion(xscVersion), err } @@ -93,6 +117,12 @@ func ChangeWD(t *testing.T, newPath string) string { return prevDir } +func ReadOutputFromFile(t *testing.T, path string) string { + content, err := os.ReadFile(path) + assert.NoError(t, err) + return strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(string(content), "\r\n", "\n"), "/", string(filepath.Separator)), "<"+string(filepath.Separator), "= minViolations, fmt.Sprintf("Expected at least %d violations in scan results, but got %d violations.", minViolations, len(violations))) - assert.True(t, len(vulnerabilities) >= minVulnerabilities, fmt.Sprintf("Expected at least %d vulnerabilities in scan results, but got %d vulnerabilities.", minVulnerabilities, len(vulnerabilities))) - assert.True(t, len(licenses) >= minLicenses, fmt.Sprintf("Expected at least %d Licenses in scan results, but got %d Licenses.", minLicenses, len(licenses))) - } -} - -func VerifySimpleJsonScanResults(t *testing.T, content string, minViolations, minVulnerabilities, minLicenses int) { - var results formats.SimpleJsonResults - err := json.Unmarshal([]byte(content), &results) - if assert.NoError(t, err) { - assert.GreaterOrEqual(t, len(results.SecurityViolations), minViolations) - assert.GreaterOrEqual(t, len(results.Vulnerabilities), minVulnerabilities) - assert.GreaterOrEqual(t, len(results.Licenses), minLicenses) - } -} - -func VerifySimpleJsonJasResults(t *testing.T, content string, minSastViolations, minIacViolations, minSecrets, - minApplicable, minUndetermined, minNotCovered, minNotApplicable int) { - var results formats.SimpleJsonResults - err := json.Unmarshal([]byte(content), &results) - if assert.NoError(t, err) { - assert.GreaterOrEqual(t, len(results.Sast), minSastViolations, "Found less sast then expected") - assert.GreaterOrEqual(t, len(results.Secrets), minSecrets, "Found less secrets then expected") - assert.GreaterOrEqual(t, len(results.Iacs), minIacViolations, "Found less IaC then expected") - var applicableResults, undeterminedResults, notCoveredResults, notApplicableResults int - for _, vuln := range results.Vulnerabilities { - switch vuln.Applicable { - case string(jasutils.NotApplicable): - notApplicableResults++ - case string(jasutils.Applicable): - applicableResults++ - case string(jasutils.NotCovered): - notCoveredResults++ - case string(jasutils.ApplicabilityUndetermined): - undeterminedResults++ - } - } - assert.GreaterOrEqual(t, applicableResults, minApplicable, "Found less applicableResults then expected") - assert.GreaterOrEqual(t, undeterminedResults, minUndetermined, "Found less undeterminedResults then expected") - assert.GreaterOrEqual(t, notCoveredResults, minNotCovered, "Found less notCoveredResults then expected") - assert.GreaterOrEqual(t, notApplicableResults, minNotApplicable, "Found less notApplicableResults then expected") - } -} diff --git a/utils/results/conversion/convertor_test.go b/utils/results/conversion/convertor_test.go new file mode 100644 index 00000000..b5f66978 --- /dev/null +++ b/utils/results/conversion/convertor_test.go @@ -0,0 +1,153 @@ +package conversion + +import ( + "encoding/json" + "fmt" + "path/filepath" + "testing" + + "github.com/jfrog/jfrog-cli-security/tests/utils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/validations" + "github.com/owenrumney/go-sarif/v2/sarif" + "github.com/stretchr/testify/assert" +) + +var ( + testDataDir = filepath.Join("..", "..", "..", "testdata", "other", "output", "formats") +) + +const ( + SimpleJson conversionFormat = "simple-json" + Sarif conversionFormat = "sarif" + Table conversionFormat = "table" + Summary conversionFormat = "summary" +) + +type conversionFormat string + +func getValidationParams(t *testing.T) validations.ValidationParams { + return validations.ValidationParams{ + ExactResultsMatch: true, + + Vulnerabilities: 12, + Applicable: 1, + NotApplicable: 7, + NotCovered: 4, + + Sast: 2, + Secrets: 5, + } +} + +func TestConvertResults(t *testing.T) { + var inputResults *results.SecurityCommandResults + if !assert.NoError(t, json.Unmarshal([]byte(utils.ReadOutputFromFile(t, filepath.Join(testDataDir, "audit_results.json"))), &inputResults)) { + return + } + + testCases := []struct { + contentFormat conversionFormat + expectedContentPath string + }{ + { + contentFormat: SimpleJson, + expectedContentPath: filepath.Join(testDataDir, "audit_simple_json.json"), + }, + { + contentFormat: Sarif, + expectedContentPath: filepath.Join(testDataDir, "audit_sarif.json"), + }, + { + contentFormat: Table, + expectedContentPath: filepath.Join(testDataDir, "audit_table.json"), + }, + { + contentFormat: Summary, + expectedContentPath: filepath.Join(testDataDir, "audit_summary.json"), + }, + } + + for _, testCase := range testCases { + t.Run(fmt.Sprintf("Convert to %s", testCase.contentFormat), func(t *testing.T) { + validationParams := getValidationParams(t) + convertor := NewCommandResultsConvertor(ResultConvertParams{}) + + switch testCase.contentFormat { + case SimpleJson: + validateSimpleJsonConversion(t, []byte(utils.ReadOutputFromFile(t, testCase.expectedContentPath)), inputResults, convertor, validationParams) + case Sarif: + validateSarifConversion(t, []byte(utils.ReadOutputFromFile(t, testCase.expectedContentPath)), inputResults, convertor, validationParams) + case Table: + validateTableConversion(t, []byte(utils.ReadOutputFromFile(t, testCase.expectedContentPath)), inputResults, convertor, validationParams) + case Summary: + validateSummaryConversion(t, []byte(utils.ReadOutputFromFile(t, testCase.expectedContentPath)), inputResults, convertor, validationParams) + } + }) + } +} + +func validateSimpleJsonConversion(t *testing.T, expectedContent []byte, inputResults *results.SecurityCommandResults, convertor *CommandResultsConvertor, validationParams validations.ValidationParams) { + var expectedResults formats.SimpleJsonResults + if !assert.NoError(t, json.Unmarshal(expectedContent, &expectedResults)) { + return + } + validationParams.Expected = expectedResults + + actualResults, err := convertor.ConvertToSimpleJson(inputResults) + if !assert.NoError(t, err) { + return + } + validationParams.Actual = actualResults + + validations.ValidateCommandSimpleJsonOutput(t, validationParams) +} + +func validateSarifConversion(t *testing.T, expectedContent []byte, inputResults *results.SecurityCommandResults, convertor *CommandResultsConvertor, validationParams validations.ValidationParams) { + var expectedResults *sarif.Report + if !assert.NoError(t, json.Unmarshal(expectedContent, &expectedResults)) { + return + } + validationParams.Expected = expectedResults + + actualResults, err := convertor.ConvertToSarif(inputResults) + if !assert.NoError(t, err) { + return + } + validationParams.Actual = actualResults + + validations.ValidateCommandSarifOutput(t, validationParams) +} + +func validateTableConversion(t *testing.T, expectedContent []byte, inputResults *results.SecurityCommandResults, convertor *CommandResultsConvertor, validationParams validations.ValidationParams) { + var expectedResults formats.ResultsTables + if !assert.NoError(t, json.Unmarshal(expectedContent, &expectedResults)) { + return + } + validationParams.Expected = expectedResults + + actualResults, err := convertor.ConvertToTable(inputResults) + if !assert.NoError(t, err) { + return + } + validationParams.Actual = actualResults + + validations.ValidateCommandTableOutput(t, validationParams) +} + +func validateSummaryConversion(t *testing.T, expectedContent []byte, inputResults *results.SecurityCommandResults, convertor *CommandResultsConvertor, validationParams validations.ValidationParams) { + var expectedResults formats.SummaryResults + if !assert.NoError(t, json.Unmarshal(expectedContent, &expectedResults)) { + return + } + validationParams.Expected = expectedResults + + actualResults, err := convertor.ConvertToSummary(inputResults) + if !assert.NoError(t, err) { + return + } + validationParams.Actual = actualResults + + validations.ValidateCommandSummaryOutput(t, validationParams) +} diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index f54d94e1..db524c66 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -167,8 +167,8 @@ func (sc *CmdResultsSarifConverter) addScaResultsToCurrentRun(rules map[string]* } func PrepareSarifScaViolations(target string, run *sarif.Run, pretty, entitledForJas bool, violations []services.Violation, applicabilityRuns ...*sarif.Run) ([]*sarif.Result, map[string]*sarif.ReportingDescriptor, error) { - var sarifResults []*sarif.Result - var rules map[string]*sarif.ReportingDescriptor + sarifResults := []*sarif.Result{} + rules := map[string]*sarif.ReportingDescriptor{} err := results.PrepareScaViolations( target, violations, @@ -184,8 +184,8 @@ func PrepareSarifScaViolations(target string, run *sarif.Run, pretty, entitledFo } func PrepareSarifScaVulnerabilities(target string, vulnerabilities []services.Vulnerability, pretty, entitledForJas bool, applicabilityRuns ...*sarif.Run) ([]*sarif.Result, map[string]*sarif.ReportingDescriptor, error) { - var sarifResults []*sarif.Result - var rules map[string]*sarif.ReportingDescriptor + sarifResults := []*sarif.Result{} + rules := map[string]*sarif.ReportingDescriptor{} err := results.PrepareScaVulnerabilities( target, vulnerabilities, diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go index 9adb04ff..c0207c8f 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go @@ -57,7 +57,7 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseViolations(target string, _ techu if sjc.current == nil { return results.ConvertorResetErr } - secViolationsSimpleJson, licViolationsSimpleJson, opRiskViolationsSimpleJson, err := PrepareSimpleJsonViolations(target, violations, sjc.entitledForJas, sjc.pretty, applicabilityRuns...) + secViolationsSimpleJson, licViolationsSimpleJson, opRiskViolationsSimpleJson, err := PrepareSimpleJsonViolations(target, violations, sjc.pretty, sjc.entitledForJas, applicabilityRuns...) if err != nil { return } @@ -71,7 +71,7 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseVulnerabilities(target string, _ if sjc.current == nil { return results.ConvertorResetErr } - vulSimpleJson, err := PrepareSimpleJsonVulnerabilities(target, vulnerabilities, sjc.entitledForJas, sjc.pretty, applicabilityRuns...) + vulSimpleJson, err := PrepareSimpleJsonVulnerabilities(target, vulnerabilities, sjc.pretty, sjc.entitledForJas, applicabilityRuns...) if err != nil || len(vulSimpleJson) == 0 { return } @@ -136,15 +136,15 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseSast(target string, sast ...*sari return } -func PrepareSimpleJsonViolations(target string, violations []services.Violation, jasEntitled, pretty bool, applicabilityRuns ...*sarif.Run) ([]formats.VulnerabilityOrViolationRow, []formats.LicenseRow, []formats.OperationalRiskViolationRow, error) { +func PrepareSimpleJsonViolations(target string, violations []services.Violation, pretty, jasEntitled bool, applicabilityRuns ...*sarif.Run) ([]formats.VulnerabilityOrViolationRow, []formats.LicenseRow, []formats.OperationalRiskViolationRow, error) { var securityViolationsRows []formats.VulnerabilityOrViolationRow var licenseViolationsRows []formats.LicenseRow var operationalRiskViolationsRows []formats.OperationalRiskViolationRow err := results.PrepareScaViolations( target, violations, - jasEntitled, pretty, + jasEntitled, applicabilityRuns, addSimpleJsonSecurityViolation(&securityViolationsRows, pretty), addSimpleJsonLicenseViolation(&licenseViolationsRows, pretty), @@ -153,13 +153,13 @@ func PrepareSimpleJsonViolations(target string, violations []services.Violation, return securityViolationsRows, licenseViolationsRows, operationalRiskViolationsRows, err } -func PrepareSimpleJsonVulnerabilities(target string, vulnerabilities []services.Vulnerability, entitledForJas, pretty bool, applicabilityRuns ...*sarif.Run) ([]formats.VulnerabilityOrViolationRow, error) { +func PrepareSimpleJsonVulnerabilities(target string, vulnerabilities []services.Vulnerability, pretty, entitledForJas bool, applicabilityRuns ...*sarif.Run) ([]formats.VulnerabilityOrViolationRow, error) { var vulnerabilitiesRows []formats.VulnerabilityOrViolationRow err := results.PrepareScaVulnerabilities( target, vulnerabilities, - entitledForJas, pretty, + entitledForJas, applicabilityRuns, addSimpleJsonVulnerability(&vulnerabilitiesRows, pretty), ) @@ -360,19 +360,13 @@ func sortResults(simpleJsonResults *formats.SimpleJsonResults) { }) } if len(simpleJsonResults.Secrets) > 0 { - sort.Slice(simpleJsonResults.Secrets, func(i, j int) bool { - return simpleJsonResults.Secrets[i].SeverityNumValue > simpleJsonResults.Secrets[j].SeverityNumValue - }) + sortSourceCodeRow(simpleJsonResults.Secrets) } if len(simpleJsonResults.Iacs) > 0 { - sort.Slice(simpleJsonResults.Iacs, func(i, j int) bool { - return simpleJsonResults.Iacs[i].SeverityNumValue > simpleJsonResults.Iacs[j].SeverityNumValue - }) + sortSourceCodeRow(simpleJsonResults.Iacs) } if len(simpleJsonResults.Sast) > 0 { - sort.Slice(simpleJsonResults.Sast, func(i, j int) bool { - return simpleJsonResults.Sast[i].SeverityNumValue > simpleJsonResults.Sast[j].SeverityNumValue - }) + sortSourceCodeRow(simpleJsonResults.Sast) } } @@ -385,6 +379,15 @@ func sortVulnerabilityOrViolationRows(rows []formats.VulnerabilityOrViolationRow }) } +func sortSourceCodeRow(rows []formats.SourceCodeRow) { + sort.Slice(rows, func(i, j int) bool { + if rows[i].SeverityNumValue != rows[j].SeverityNumValue { + return rows[i].SeverityNumValue > rows[j].SeverityNumValue + } + return rows[i].Location.File > rows[j].Location.File + }) +} + func convertJfrogResearchInformation(extendedInfo *services.ExtendedInformation) *formats.JfrogResearchInformation { if extendedInfo == nil { return nil diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go index ab0e2ff8..925d9641 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go @@ -336,7 +336,7 @@ func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - out, err := PrepareSimpleJsonVulnerabilities(tc.target, tc.input, tc.entitledForJas, tc.pretty, tc.applicablityRuns...) + out, err := PrepareSimpleJsonVulnerabilities(tc.target, tc.input, tc.pretty, tc.entitledForJas, tc.applicablityRuns...) assert.NoError(t, err) assert.ElementsMatch(t, tc.expectedOutput, out) }) @@ -486,7 +486,7 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - securityOutput, licenseOutput, operationalRiskOutput, err := PrepareSimpleJsonViolations(tc.target, tc.input, tc.entitledForJas, tc.pretty, tc.applicablityRuns...) + securityOutput, licenseOutput, operationalRiskOutput, err := PrepareSimpleJsonViolations(tc.target, tc.input, tc.pretty, tc.entitledForJas, tc.applicablityRuns...) assert.NoError(t, err) assert.ElementsMatch(t, tc.expectedSecurityOutput, securityOutput) assert.ElementsMatch(t, tc.expectedLicenseOutput, licenseOutput) diff --git a/utils/results/conversion/summaryparser/summaryparser.go b/utils/results/conversion/summaryparser/summaryparser.go index 135b9805..6d68ddf1 100644 --- a/utils/results/conversion/summaryparser/summaryparser.go +++ b/utils/results/conversion/summaryparser/summaryparser.go @@ -56,17 +56,11 @@ func (sc *CmdResultsSummaryConverter) ParseViolations(target string, _ techutils if sc.currentScan == nil { return results.ConvertorNewScanErr } - if sc.currentScan.Vulnerabilities == nil { - sc.currentScan.Vulnerabilities = &formats.ScanVulnerabilitiesSummary{} - } - if sc.currentScan.Vulnerabilities.ScaScanResults == nil { - sc.currentScan.Vulnerabilities.ScaScanResults = &formats.ScanScaResult{} - } err = results.PrepareScaViolations( target, violations, - sc.entitledForJas, false, + sc.entitledForJas, applicabilityRuns, sc.getScaViolationHandler(), sc.getScaViolationHandler(), @@ -77,6 +71,12 @@ func (sc *CmdResultsSummaryConverter) ParseViolations(target string, _ techutils func (sc *CmdResultsSummaryConverter) getScaViolationHandler() results.PrepareScaViolationFunc { return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) (err error) { + if sc.currentScan.Violations == nil { + sc.currentScan.Violations = formats.TwoLevelSummaryCount{} + } + if sc.currentScan.Violations[violation.ViolationType] == nil { + sc.currentScan.Violations[violation.ViolationType] = formats.SummaryCount{} + } for i := 0; i < len(getCveIds(cves, violation.IssueId)); i++ { sc.currentScan.Violations[violation.ViolationType][severity.String()]++ } @@ -91,26 +91,15 @@ func (sc *CmdResultsSummaryConverter) ParseVulnerabilities(target string, tech t if sc.currentScan == nil { return results.ConvertorNewScanErr } - if sc.currentScan.Vulnerabilities == nil { - sc.currentScan.Vulnerabilities = &formats.ScanVulnerabilitiesSummary{} - } - if sc.currentScan.Vulnerabilities.ScaScanResults == nil { - sc.currentScan.Vulnerabilities.ScaScanResults = &formats.ScanScaResult{} - } err = results.PrepareScaVulnerabilities( target, vulnerabilities, - sc.entitledForJas, false, + sc.entitledForJas, applicabilityRuns, func(vulnerability services.Vulnerability, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { for _, id := range getCveIds(cves, vulnerability.IssueId) { - issueId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, id) - if !sc.currentCveUnique.Exists(issueId) { - sc.currentScan.Vulnerabilities.ScaScanResults.UniqueFindings++ - sc.currentCveUnique.Add(issueId) - } - sc.currentScan.Vulnerabilities.ScaScanResults.SummaryCount[severity.String()][applicabilityStatus.String()]++ + sc.addVulnerabilityToScanSummaryResult(id, impactedPackagesName, impactedPackagesVersion, severity, applicabilityStatus) } return nil }, @@ -118,6 +107,27 @@ func (sc *CmdResultsSummaryConverter) ParseVulnerabilities(target string, tech t return } +func (sc *CmdResultsSummaryConverter) addVulnerabilityToScanSummaryResult(id, impactedPackagesName, impactedPackagesVersion string, severity severityutils.Severity, applicabilityStatus jasutils.ApplicabilityStatus) { + if sc.currentScan.Vulnerabilities == nil { + sc.currentScan.Vulnerabilities = &formats.ScanVulnerabilitiesSummary{} + } + if sc.currentScan.Vulnerabilities.ScaScanResults == nil { + sc.currentScan.Vulnerabilities.ScaScanResults = &formats.ScanScaResult{SummaryCount: formats.TwoLevelSummaryCount{}} + } + if sc.currentScan.Vulnerabilities.ScaScanResults.SummaryCount == nil { + sc.currentScan.Vulnerabilities.ScaScanResults.SummaryCount = formats.TwoLevelSummaryCount{} + } + if sc.currentScan.Vulnerabilities.ScaScanResults.SummaryCount[severity.String()] == nil { + sc.currentScan.Vulnerabilities.ScaScanResults.SummaryCount[severity.String()] = formats.SummaryCount{} + } + issueId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, id) + if !sc.currentCveUnique.Exists(issueId) { + sc.currentScan.Vulnerabilities.ScaScanResults.UniqueFindings++ + sc.currentCveUnique.Add(issueId) + } + sc.currentScan.Vulnerabilities.ScaScanResults.SummaryCount[severity.String()][applicabilityStatus.String()]++ +} + func getCveIds(cves []formats.CveRow, issueId string) []string { ids := []string{} for _, cve := range cves { diff --git a/utils/results/conversion/tableparser/tableparser.go b/utils/results/conversion/tableparser/tableparser.go index be7f1af8..b22f0291 100644 --- a/utils/results/conversion/tableparser/tableparser.go +++ b/utils/results/conversion/tableparser/tableparser.go @@ -22,7 +22,7 @@ func NewCmdResultsTableConverter(pretty bool) *CmdResultsTableConverter { func (tc *CmdResultsTableConverter) Get() *formats.ResultsTables { simpleJsonFormat := tc.simpleJsonConvertor.Get() - if simpleJsonFormat != nil { + if simpleJsonFormat == nil { return &formats.ResultsTables{} } return &formats.ResultsTables{ diff --git a/utils/results/output/securityJobSummary_test.go b/utils/results/output/securityJobSummary_test.go index 259c15c3..1fb027e5 100644 --- a/utils/results/output/securityJobSummary_test.go +++ b/utils/results/output/securityJobSummary_test.go @@ -3,9 +3,9 @@ package output import ( "os" "path/filepath" - "strings" "testing" + "github.com/jfrog/jfrog-cli-security/tests/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/stretchr/testify/assert" ) @@ -123,7 +123,7 @@ func TestConvertSummaryToString(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { // Read expected content from file - expectedContent := getOutputFromFile(t, testCase.expectedContentPath) + expectedContent := utils.ReadOutputFromFile(t, testCase.expectedContentPath) summary, err := ConvertSummaryToString(testCase.summary) assert.NoError(t, err) assert.Equal(t, expectedContent, summary) @@ -131,11 +131,11 @@ func TestConvertSummaryToString(t *testing.T) { } } -func getOutputFromFile(t *testing.T, path string) string { - content, err := os.ReadFile(path) - assert.NoError(t, err) - return strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(string(content), "\r\n", "\n"), "/", string(filepath.Separator)), "<"+string(filepath.Separator), "= minViolations, fmt.Sprintf("Expected at least %d violations in scan results, but got %d violations.", minViolations, len(violations))) +// assert.True(t, len(vulnerabilities) >= minVulnerabilities, fmt.Sprintf("Expected at least %d vulnerabilities in scan results, but got %d vulnerabilities.", minVulnerabilities, len(vulnerabilities))) +// assert.True(t, len(licenses) >= minLicenses, fmt.Sprintf("Expected at least %d Licenses in scan results, but got %d Licenses.", minLicenses, len(licenses))) +// } +// } + +// func VerifySimpleJsonScanResults(t *testing.T, content string, minViolations, minVulnerabilities, minLicenses int) { +// var results formats.SimpleJsonResults +// err := json.Unmarshal([]byte(content), &results) +// if assert.NoError(t, err) { +// assert.GreaterOrEqual(t, len(results.SecurityViolations), minViolations) +// assert.GreaterOrEqual(t, len(results.Vulnerabilities), minVulnerabilities) +// assert.GreaterOrEqual(t, len(results.Licenses), minLicenses) +// } +// } \ No newline at end of file diff --git a/utils/xsc/analyticsmetrics_test.go b/utils/xsc/analyticsmetrics_test.go index 0224a199..561300a7 100644 --- a/utils/xsc/analyticsmetrics_test.go +++ b/utils/xsc/analyticsmetrics_test.go @@ -10,6 +10,7 @@ import ( "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/validations" "github.com/jfrog/jfrog-client-go/utils/tests" "github.com/jfrog/jfrog-client-go/xray/services" xscservices "github.com/jfrog/jfrog-client-go/xsc/services" @@ -30,19 +31,19 @@ func TestCalcShouldReportEvents(t *testing.T) { defer reportUsageCallback() // Minimum Xsc version. - mockServer, serverDetails := utils.XscServer(t, xscservices.AnalyticsMetricsMinXscVersion) + mockServer, serverDetails := validations.XscServer(t, xscservices.AnalyticsMetricsMinXscVersion) defer mockServer.Close() am := NewAnalyticsMetricsService(serverDetails) assert.True(t, am.calcShouldReportEvents()) // Lower Xsc version. - mockServerLowerVersion, serverDetails := utils.XscServer(t, lowerAnalyticsMetricsMinXscVersion) + mockServerLowerVersion, serverDetails := validations.XscServer(t, lowerAnalyticsMetricsMinXscVersion) defer mockServerLowerVersion.Close() am = NewAnalyticsMetricsService(serverDetails) assert.False(t, am.calcShouldReportEvents()) // Higher Xsc version. - mockServerHigherVersion, serverDetails := utils.XscServer(t, higherAnalyticsMetricsMinXscVersion) + mockServerHigherVersion, serverDetails := validations.XscServer(t, higherAnalyticsMetricsMinXscVersion) defer mockServerHigherVersion.Close() am = NewAnalyticsMetricsService(serverDetails) assert.True(t, am.calcShouldReportEvents()) @@ -61,11 +62,11 @@ func TestAddGeneralEvent(t *testing.T) { usageCallback := tests.SetEnvWithCallbackAndAssert(t, coreutils.ReportUsage, "true") defer usageCallback() // Successful flow. - mockServer, serverDetails := utils.XscServer(t, xscservices.AnalyticsMetricsMinXscVersion) + mockServer, serverDetails := validations.XscServer(t, xscservices.AnalyticsMetricsMinXscVersion) defer mockServer.Close() am := NewAnalyticsMetricsService(serverDetails) am.AddGeneralEvent(am.CreateGeneralEvent(xscservices.CliProduct, xscservices.CliEventType)) - assert.Equal(t, utils.TestMsi, am.GetMsi()) + assert.Equal(t, validations.TestMsi, am.GetMsi()) // In case cli should not report analytics, verify that request won't be sent. am.shouldReportEvents = false @@ -88,7 +89,7 @@ func TestAnalyticsMetricsService_createAuditResultsFromXscAnalyticsBasicGeneralE {name: "Scan failed with findings.", auditResults: getDummyContentForGeneralEvent(false, true), want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 1, EventStatus: xscservices.Failed}}, {name: "Scan failed no findings.", auditResults: &results.SecurityCommandResults{Targets: []*results.TargetResults{{Errors: []error{errors.New("an error")}}}}, want: xscservices.XscAnalyticsBasicGeneralEvent{TotalFindings: 0, EventStatus: xscservices.Failed}}, } - mockServer, serverDetails := utils.XscServer(t, xscservices.AnalyticsMetricsMinXscVersion) + mockServer, serverDetails := validations.XscServer(t, xscservices.AnalyticsMetricsMinXscVersion) defer mockServer.Close() am := NewAnalyticsMetricsService(serverDetails) am.SetStartTime() @@ -110,7 +111,7 @@ func getDummyContentForGeneralEvent(withJas, withErr bool) *results.SecurityComm cmdResults := results.NewCommandResults("", true) scanResults := cmdResults.NewScanResults(results.ScanTarget{Target: "target"}) - scanResults.NewScaScanResults(&services.ScanResponse{Vulnerabilities: vulnerabilities}) + scanResults.NewScaScanResults(services.ScanResponse{Vulnerabilities: vulnerabilities}) if withJas { scanResults.JasResults.ApplicabilityScanResults = []*sarif.Run{sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyPassingResult("applic_CVE-123"))} diff --git a/utils/xsc/errorreport_test.go b/utils/xsc/errorreport_test.go index 11b839d5..2fc77db8 100644 --- a/utils/xsc/errorreport_test.go +++ b/utils/xsc/errorreport_test.go @@ -7,7 +7,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/validations" clienttestutils "github.com/jfrog/jfrog-client-go/utils/tests" "github.com/stretchr/testify/assert" ) @@ -27,7 +27,7 @@ func TestReportLogErrorEventPossible(t *testing.T) { }{ { serverCreationFunc: func() (*httptest.Server, *config.ServerDetails) { - serverMock, serverDetails, _ := utils.CreateXscRestsMockServer(t, func(w http.ResponseWriter, r *http.Request) { + serverMock, serverDetails, _ := validations.CreateXscRestsMockServer(t, func(w http.ResponseWriter, r *http.Request) { if r.RequestURI == "/xsc/api/v1/system/version" { w.WriteHeader(http.StatusNotFound) _, innerError := w.Write([]byte("Xsc service is not enabled")) @@ -41,18 +41,18 @@ func TestReportLogErrorEventPossible(t *testing.T) { expectedResponse: false, }, { - serverCreationFunc: func() (*httptest.Server, *config.ServerDetails) { return utils.XscServer(t, "") }, + serverCreationFunc: func() (*httptest.Server, *config.ServerDetails) { return validations.XscServer(t, "") }, expectedResponse: false, }, { serverCreationFunc: func() (*httptest.Server, *config.ServerDetails) { - return utils.XscServer(t, unsupportedXscVersionForErrorLogs) + return validations.XscServer(t, unsupportedXscVersionForErrorLogs) }, expectedResponse: false, }, { serverCreationFunc: func() (*httptest.Server, *config.ServerDetails) { - return utils.XscServer(t, supportedXscVersionForErrorLogs) + return validations.XscServer(t, supportedXscVersionForErrorLogs) }, expectedResponse: true, }, diff --git a/xsc_test.go b/xsc_test.go index a929ad00..09bb84d9 100644 --- a/xsc_test.go +++ b/xsc_test.go @@ -13,6 +13,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/validations" "github.com/jfrog/jfrog-cli-security/utils/xray/scangraph" "github.com/jfrog/jfrog-cli-security/utils/xsc" @@ -57,28 +58,40 @@ func TestXscAuditNpmJsonWithWatch(t *testing.T) { restoreFunc := initXscTest(t) defer restoreFunc() output := testAuditNpm(t, string(format.Json)) - securityTestUtils.VerifyJsonScanResults(t, output, 1, 0, 1) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + SecurityViolations: 1, + Licenses: 1, + }) } func TestXscAuditNpmSimpleJsonWithWatch(t *testing.T) { restoreFunc := initXscTest(t) defer restoreFunc() output := testAuditNpm(t, string(format.SimpleJson)) - securityTestUtils.VerifySimpleJsonScanResults(t, output, 1, 0, 1) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + SecurityViolations: 1, + Licenses: 1, + }) } func TestXscAuditMavenJson(t *testing.T) { restoreFunc := initXscTest(t) defer restoreFunc() output := testXscAuditMaven(t, string(format.Json)) - securityTestUtils.VerifyJsonScanResults(t, output, 0, 1, 1) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) } func TestXscAuditMavenSimpleJson(t *testing.T) { restoreFunc := initXscTest(t) defer restoreFunc() output := testXscAuditMaven(t, string(format.SimpleJson)) - securityTestUtils.VerifySimpleJsonScanResults(t, output, 0, 1, 1) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) } func TestXscAnalyticsForAudit(t *testing.T) { From 1d9ff3e1413b49b16e2297830aeb3edc1cb3e552 Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 14 Jul 2024 18:39:02 +0300 Subject: [PATCH 13/82] format --- audit_test.go | 125 ++++++++++-------- scans_test.go | 12 +- utils/results/conversion/convertor_test.go | 4 +- utils/validations/test_validate_sarif.go | 4 +- .../validations/test_validate_simple_json.go | 64 +++++---- utils/validations/test_validate_summary.go | 2 +- utils/validations/test_validate_table.go | 2 +- utils/validations/test_validation.go | 4 +- xsc_test.go | 8 +- 9 files changed, 118 insertions(+), 107 deletions(-) diff --git a/audit_test.go b/audit_test.go index 2403d95d..31bb419d 100644 --- a/audit_test.go +++ b/audit_test.go @@ -37,7 +37,7 @@ func TestXrayAuditNpmJson(t *testing.T) { output := testAuditNpm(t, string(format.Json)) validations.VerifyJsonResults(t, output, validations.ValidationParams{ SecurityViolations: 1, - Licenses: 1, + Licenses: 1, }) } @@ -45,7 +45,7 @@ func TestXrayAuditNpmSimpleJson(t *testing.T) { output := testAuditNpm(t, string(format.SimpleJson)) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ SecurityViolations: 1, - Licenses: 1, + Licenses: 1, }) } @@ -71,7 +71,7 @@ func TestXrayAuditPnpmJson(t *testing.T) { output := testXrayAuditPnpm(t, string(format.Json)) validations.VerifyJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, - Licenses: 1, + Licenses: 1, }) } @@ -79,7 +79,7 @@ func TestXrayAuditPnpmSimpleJson(t *testing.T) { output := testXrayAuditPnpm(t, string(format.SimpleJson)) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, - Licenses: 1, + Licenses: 1, }) } @@ -104,7 +104,7 @@ func TestXrayAuditYarnV2Json(t *testing.T) { output := runXrayAuditYarnWithOutput(t, string(format.Json)) validations.VerifyJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, - Licenses: 1, + Licenses: 1, }) }) } @@ -114,7 +114,7 @@ func TestXrayAuditYarnV2SimpleJson(t *testing.T) { output := runXrayAuditYarnWithOutput(t, string(format.SimpleJson)) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, - Licenses: 1, + Licenses: 1, }) }) } @@ -124,7 +124,7 @@ func TestXrayAuditYarnV1Json(t *testing.T) { output := runXrayAuditYarnWithOutput(t, string(format.Json)) validations.VerifyJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, - Licenses: 1, + Licenses: 1, }) }) } @@ -146,7 +146,7 @@ func TestXrayAuditYarnV1SimpleJson(t *testing.T) { output := runXrayAuditYarnWithOutput(t, string(format.SimpleJson)) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, - Licenses: 1, + Licenses: 1, }) }) } @@ -223,7 +223,7 @@ func TestXrayAuditNugetJson(t *testing.T) { output := testXrayAuditNuget(t, test.projectName, test.format, test.restoreTech) validations.VerifyJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: test.minVulnerabilities, - Licenses: test.minLicences, + Licenses: test.minLicences, }) }) } @@ -266,7 +266,7 @@ func TestXrayAuditNugetSimpleJson(t *testing.T) { output := testXrayAuditNuget(t, test.projectName, test.format, test.restoreTech) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: test.minVulnerabilities, - Licenses: test.minLicences, + Licenses: test.minLicences, }) }) } @@ -295,7 +295,7 @@ func TestXrayAuditGradleJson(t *testing.T) { output := testXrayAuditGradle(t, string(format.Json)) validations.VerifyJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 3, - Licenses: 3, + Licenses: 3, }) } @@ -303,7 +303,7 @@ func TestXrayAuditGradleSimpleJson(t *testing.T) { output := testXrayAuditGradle(t, string(format.SimpleJson)) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 3, - Licenses: 3, + Licenses: 3, }) } @@ -323,12 +323,18 @@ func testXrayAuditGradle(t *testing.T, format string) string { func TestXrayAuditMavenJson(t *testing.T) { output := testXscAuditMaven(t, string(format.Json)) - validations.VerifyJsonScanResults(t, output, 0, 1, 1) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) } func TestXrayAuditMavenSimpleJson(t *testing.T) { output := testXscAuditMaven(t, string(format.SimpleJson)) - validations.VerifySimpleJsonScanResults(t, output, 0, 1, 1) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Licenses: 1, + }) } func testXscAuditMaven(t *testing.T, format string) string { @@ -372,40 +378,44 @@ func TestXrayAuditMultiProjects(t *testing.T) { securityTestUtils.CreateJfrogHomeConfig(t, true) defer securityTestUtils.CleanTestsHomeEnv() output := securityTests.PlatformCli.WithoutCredentials().RunCliCmdWithOutput(t, "audit", "--format="+string(format.SimpleJson), workingDirsFlag) - - VerifySimpleJsonResults(t, output, validations.ValidationParams{ - Sast: 1, - Iac: 9, + + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Sast: 1, + Iac: 9, Secrets: 6, Vulnerabilities: 35, - Applicable: 3, - Undetermined: 0, - NotCovered: 25, - NotApplicable: 2, + Applicable: 3, + Undetermined: 0, + NotCovered: 25, + NotApplicable: 2, }) - // validations.VerifySimpleJsonScanResults(t, output, 0, 35, 0) - // validations.VerifySimpleJsonJasResults(t, output, 1, 9, 6, 3, 0, 25, 2) } func TestXrayAuditPipJson(t *testing.T) { output := testXrayAuditPip(t, string(format.Json), "") - validations.VerifyJsonScanResults(t, output, 0, 3, 1) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 3, + Licenses: 1, + }) } func TestXrayAuditPipSimpleJson(t *testing.T) { output := testXrayAuditPip(t, string(format.SimpleJson), "") - validations.VerifySimpleJsonScanResults(t, output, 0, 3, 1) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 3, + Licenses: 1, + }) } func TestXrayAuditPipJsonWithRequirementsFile(t *testing.T) { output := testXrayAuditPip(t, string(format.Json), "requirements.txt") - validations.VerifyJsonScanResults(t, output, 0, 2, 0) + validations.VerifyJsonResults(t, output, validations.ValidationParams{Vulnerabilities: 2}) } func TestXrayAuditPipSimpleJsonWithRequirementsFile(t *testing.T) { output := testXrayAuditPip(t, string(format.SimpleJson), "requirements.txt") - validations.VerifySimpleJsonScanResults(t, output, 0, 2, 0) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{Vulnerabilities: 2}) } func testXrayAuditPip(t *testing.T, format, requirementsFile string) string { @@ -429,12 +439,18 @@ func testXrayAuditPip(t *testing.T, format, requirementsFile string) string { func TestXrayAuditPipenvJson(t *testing.T) { output := testXrayAuditPipenv(t, string(format.Json)) - validations.VerifyJsonScanResults(t, output, 0, 3, 1) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 3, + Licenses: 1, + }) } func TestXrayAuditPipenvSimpleJson(t *testing.T) { output := testXrayAuditPipenv(t, string(format.SimpleJson)) - validations.VerifySimpleJsonScanResults(t, output, 0, 3, 1) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 3, + Licenses: 1, + }) } func testXrayAuditPipenv(t *testing.T, format string) string { @@ -453,12 +469,18 @@ func testXrayAuditPipenv(t *testing.T, format string) string { func TestXrayAuditPoetryJson(t *testing.T) { output := testXrayAuditPoetry(t, string(format.Json)) - validations.VerifyJsonScanResults(t, output, 0, 3, 1) + validations.VerifyJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 3, + Licenses: 1, + }) } func TestXrayAuditPoetrySimpleJson(t *testing.T) { output := testXrayAuditPoetry(t, string(format.SimpleJson)) - validations.VerifySimpleJsonScanResults(t, output, 0, 3, 1) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 3, + Licenses: 1, + }) } func testXrayAuditPoetry(t *testing.T, format string) string { @@ -491,11 +513,7 @@ func TestXrayAuditNotEntitledForJas(t *testing.T) { cliToRun, cleanUp := securityTestUtils.InitTestWithMockCommandOrParams(t, getNoJasAuditMockCommand) defer cleanUp() output := testXrayAuditJas(t, cliToRun, filepath.Join("jas", "jas"), "3") - VerifySimpleJsonResults(t, output, validations.ValidationParams{Vulnerabilities: 8}) - // Verify that scan results are printed - // validations.VerifySimpleJsonScanResults(t, output, 0, 8, 0) - // Verify that JAS results are not printed - // validations.VerifySimpleJsonJasResults(t, output, 0, 0, 0, 0, 0, 0, 0) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{Vulnerabilities: 8}) } func getNoJasAuditMockCommand(t *testing.T) components.Command { @@ -516,31 +534,29 @@ func getNoJasAuditMockCommand(t *testing.T) components.Command { func TestXrayAuditJasSimpleJson(t *testing.T) { output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("jas", "jas"), "3") - VerifySimpleJsonResults(t, output, validations.ValidationParams{ - Sast: 1, - Iac: 9, + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Sast: 1, + Iac: 9, Secrets: 6, Vulnerabilities: 8, - Applicable: 3, - NotCovered: 2, - NotApplicable: 2, + Applicable: 3, + NotCovered: 2, + NotApplicable: 2, }) - // validations.VerifySimpleJsonScanResults(t, output, 0, 8, 0) - // validations.VerifySimpleJsonJasResults(t, output, 1, 9, 6, 3, 0, 2, 2) } func TestXrayAuditJasSimpleJsonWithOneThread(t *testing.T) { output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("jas", "jas"), "1") validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ - Sast: 1, - Iac: 9, + Sast: 1, + Iac: 9, Secrets: 6, Vulnerabilities: 8, - Applicable: 3, - NotCovered: 2, - NotApplicable: 2, + Applicable: 3, + NotCovered: 2, + NotApplicable: 2, }) } @@ -550,9 +566,9 @@ func TestXrayAuditJasSimpleJsonWithConfig(t *testing.T) { Secrets: 1, Vulnerabilities: 8, - Applicable: 3, - NotCovered: 2, - NotApplicable: 2, + Applicable: 3, + NotCovered: 2, + NotApplicable: 2, }) } @@ -560,7 +576,7 @@ func TestXrayAuditJasNoViolationsSimpleJson(t *testing.T) { output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("package-managers", "npm", "npm"), "3") validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, - NotApplicable: 1, + NotApplicable: 1, }) } @@ -653,4 +669,3 @@ func TestAuditOnEmptyProject(t *testing.T) { // No issues should be found in an empty project validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{}) } - diff --git a/scans_test.go b/scans_test.go index bfe9cdc4..bd159d00 100644 --- a/scans_test.go +++ b/scans_test.go @@ -51,7 +51,7 @@ func TestXrayBinaryScanJson(t *testing.T) { output := testXrayBinaryScan(t, string(format.Json)) validations.VerifyJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, - Licenses: 1, + Licenses: 1, }) } @@ -59,7 +59,7 @@ func TestXrayBinaryScanSimpleJson(t *testing.T) { output := testXrayBinaryScan(t, string(format.SimpleJson)) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, - Licenses: 1, + Licenses: 1, }) } @@ -69,7 +69,7 @@ func TestXrayBinaryScanJsonWithProgress(t *testing.T) { output := testXrayBinaryScan(t, string(format.Json)) validations.VerifyJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, - Licenses: 1, + Licenses: 1, }) } @@ -79,7 +79,7 @@ func TestXrayBinaryScanSimpleJsonWithProgress(t *testing.T) { output := testXrayBinaryScan(t, string(format.SimpleJson)) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, - Licenses: 1, + Licenses: 1, }) } @@ -105,7 +105,7 @@ func TestXrayBinaryScanWithBypassArchiveLimits(t *testing.T) { output := securityTests.PlatformCli.RunCliCmdWithOutput(t, scanArgs...) validations.VerifyJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, - Licenses: 1, + Licenses: 1, }) } @@ -189,7 +189,7 @@ func runDockerScan(t *testing.T, testCli *coreTests.JfrogCli, imageName, watchNa if assert.NotEmpty(t, output) { validations.VerifyJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: minVulnerabilities, - Licenses: minLicenses, + Licenses: minLicenses, }) } // Run docker scan on image with watch diff --git a/utils/results/conversion/convertor_test.go b/utils/results/conversion/convertor_test.go index b5f66978..973fec7e 100644 --- a/utils/results/conversion/convertor_test.go +++ b/utils/results/conversion/convertor_test.go @@ -116,7 +116,7 @@ func validateSarifConversion(t *testing.T, expectedContent []byte, inputResults return } validationParams.Actual = actualResults - + validations.ValidateCommandSarifOutput(t, validationParams) } @@ -148,6 +148,6 @@ func validateSummaryConversion(t *testing.T, expectedContent []byte, inputResult return } validationParams.Actual = actualResults - + validations.ValidateCommandSummaryOutput(t, validationParams) } diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index be74fe63..30f9fc7c 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -35,7 +35,7 @@ func ValidateSarifIssuesCount(t *testing.T, params ValidationParams, results *sa // var sast, iac, secrets, licenseViolations, applicableResults, undeterminedResults, notCoveredResults, notApplicableResults int // for _, run := range results.Runs { // for _, result := range run.Results { - + // } // } @@ -83,4 +83,4 @@ func ValidateSarifIssuesCount(t *testing.T, params ValidationParams, results *sa // assert.GreaterOrEqual(t, len(results.Licenses), params.Licenses, "Expected at least %d Licenses in scan responses, but got %d Licenses.", params.Licenses, len(results.Licenses)) // } -} \ No newline at end of file +} diff --git a/utils/validations/test_validate_simple_json.go b/utils/validations/test_validate_simple_json.go index cdb5147d..1c8408eb 100644 --- a/utils/validations/test_validate_simple_json.go +++ b/utils/validations/test_validate_simple_json.go @@ -82,8 +82,8 @@ func ValidateSimpleJsonIssuesCount(t *testing.T, params ValidationParams, result } func ValidateSimpleJsonResults(t *testing.T, exactMatch bool, expected, actual formats.SimpleJsonResults) { - validatePairs(t, exactMatch, ValidationPair{ Expected: expected.MultiScanId, Actual: actual.MultiScanId, ErrMsg: "MultiScanId mismatch" }) - validatePairs(t, false, ValidationPair{ Expected: len(expected.Errors), Actual: len(actual.Errors), ErrMsg: "Errors count mismatch" }) + validatePairs(t, exactMatch, ValidationPair{Expected: expected.MultiScanId, Actual: actual.MultiScanId, ErrMsg: "MultiScanId mismatch"}) + validatePairs(t, false, ValidationPair{Expected: len(expected.Errors), Actual: len(actual.Errors), ErrMsg: "Errors count mismatch"}) // Validate vulnerabilities for _, expectedVulnerability := range expected.Vulnerabilities { vulnerability := getVulnerabilityOrViolationByIssueId(expectedVulnerability.IssueId, actual.Vulnerabilities) @@ -112,25 +112,25 @@ func getVulnerabilityOrViolationByIssueId(issueId string, content []formats.Vuln } func validateVulnerabilityOrViolationRow(t *testing.T, exactMatch bool, expected, actual formats.VulnerabilityOrViolationRow) { - validatePairs(t, exactMatch, - ValidationPair{ Expected: expected.Summary, Actual: actual.Summary, ErrMsg: fmt.Sprintf("IssueId %s: Summary mismatch", expected.IssueId) }, - ValidationPair{ Expected: expected.Severity, Actual: actual.Severity, ErrMsg: fmt.Sprintf("IssueId %s: Severity mismatch", expected.IssueId) }, - ValidationPair{ Expected: expected.Applicable, Actual: actual.Applicable, ErrMsg: fmt.Sprintf("IssueId %s: Applicable mismatch", expected.IssueId) }, - ValidationPair{ Expected: expected.Technology, Actual: actual.Technology, ErrMsg: fmt.Sprintf("IssueId %s: Technology mismatch", expected.IssueId) }, - ValidationPair{ Expected: expected.References, Actual: actual.References, ErrMsg: fmt.Sprintf("IssueId %s: References mismatch", expected.IssueId) }, - - ValidationPair{ Expected: expected.ImpactedDependencyName, Actual: actual.ImpactedDependencyName, ErrMsg: fmt.Sprintf("IssueId %s: ImpactedDependencyName mismatch", expected.IssueId) }, - ValidationPair{ Expected: expected.ImpactedDependencyVersion, Actual: actual.ImpactedDependencyVersion, ErrMsg: fmt.Sprintf("IssueId %s: ImpactedDependencyVersion mismatch", expected.IssueId) }, - ValidationPair{ Expected: expected.ImpactedDependencyType, Actual: actual.ImpactedDependencyType, ErrMsg: fmt.Sprintf("IssueId %s: ImpactedDependencyType mismatch", expected.IssueId) }, - - ValidationPair{ Expected: expected.FixedVersions, Actual: actual.FixedVersions, ErrMsg: fmt.Sprintf("IssueId %s: FixedVersions mismatch", expected.IssueId) }, + validatePairs(t, exactMatch, + ValidationPair{Expected: expected.Summary, Actual: actual.Summary, ErrMsg: fmt.Sprintf("IssueId %s: Summary mismatch", expected.IssueId)}, + ValidationPair{Expected: expected.Severity, Actual: actual.Severity, ErrMsg: fmt.Sprintf("IssueId %s: Severity mismatch", expected.IssueId)}, + ValidationPair{Expected: expected.Applicable, Actual: actual.Applicable, ErrMsg: fmt.Sprintf("IssueId %s: Applicable mismatch", expected.IssueId)}, + ValidationPair{Expected: expected.Technology, Actual: actual.Technology, ErrMsg: fmt.Sprintf("IssueId %s: Technology mismatch", expected.IssueId)}, + ValidationPair{Expected: expected.References, Actual: actual.References, ErrMsg: fmt.Sprintf("IssueId %s: References mismatch", expected.IssueId)}, + + ValidationPair{Expected: expected.ImpactedDependencyName, Actual: actual.ImpactedDependencyName, ErrMsg: fmt.Sprintf("IssueId %s: ImpactedDependencyName mismatch", expected.IssueId)}, + ValidationPair{Expected: expected.ImpactedDependencyVersion, Actual: actual.ImpactedDependencyVersion, ErrMsg: fmt.Sprintf("IssueId %s: ImpactedDependencyVersion mismatch", expected.IssueId)}, + ValidationPair{Expected: expected.ImpactedDependencyType, Actual: actual.ImpactedDependencyType, ErrMsg: fmt.Sprintf("IssueId %s: ImpactedDependencyType mismatch", expected.IssueId)}, + + ValidationPair{Expected: expected.FixedVersions, Actual: actual.FixedVersions, ErrMsg: fmt.Sprintf("IssueId %s: FixedVersions mismatch", expected.IssueId)}, ) - if validatePairs(t, exactMatch, ValidationPair{ Expected: expected.JfrogResearchInformation, Actual: actual.JfrogResearchInformation}) && expected.JfrogResearchInformation != nil { - validatePairs(t, exactMatch, - ValidationPair{ Expected: expected.JfrogResearchInformation.Summary, Actual: actual.JfrogResearchInformation.Summary, ErrMsg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Summary mismatch", expected.IssueId) }, - ValidationPair{ Expected: expected.JfrogResearchInformation.Severity, Actual: actual.JfrogResearchInformation.Severity, ErrMsg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Severity mismatch", expected.IssueId) }, - ValidationPair{ Expected: expected.JfrogResearchInformation.Remediation, Actual: actual.JfrogResearchInformation.Remediation, ErrMsg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Remediation mismatch", expected.IssueId) }, - ValidationPair{ Expected: expected.JfrogResearchInformation.SeverityReasons, Actual: actual.JfrogResearchInformation.SeverityReasons, ErrMsg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.SeverityReasons mismatch", expected.IssueId) }, + if validatePairs(t, exactMatch, ValidationPair{Expected: expected.JfrogResearchInformation, Actual: actual.JfrogResearchInformation}) && expected.JfrogResearchInformation != nil { + validatePairs(t, exactMatch, + ValidationPair{Expected: expected.JfrogResearchInformation.Summary, Actual: actual.JfrogResearchInformation.Summary, ErrMsg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Summary mismatch", expected.IssueId)}, + ValidationPair{Expected: expected.JfrogResearchInformation.Severity, Actual: actual.JfrogResearchInformation.Severity, ErrMsg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Severity mismatch", expected.IssueId)}, + ValidationPair{Expected: expected.JfrogResearchInformation.Remediation, Actual: actual.JfrogResearchInformation.Remediation, ErrMsg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Remediation mismatch", expected.IssueId)}, + ValidationPair{Expected: expected.JfrogResearchInformation.SeverityReasons, Actual: actual.JfrogResearchInformation.SeverityReasons, ErrMsg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.SeverityReasons mismatch", expected.IssueId)}, ) } validateComponentRows(t, expected.IssueId, exactMatch, expected.Components, actual.Components) @@ -156,11 +156,11 @@ func validateComponentRows(t *testing.T, issueId string, exactMatch bool, expect } func validateComponentRow(t *testing.T, issueId string, exactMatch bool, expected, actual formats.ComponentRow) { - validatePairs(t, exactMatch, - ValidationPair{ Expected: expected.Location, Actual: actual.Location, ErrMsg: fmt.Sprintf("IssueId %s: Component %s:%s Location mismatch", issueId, expected.Name, expected.Version) }, + validatePairs(t, exactMatch, + ValidationPair{Expected: expected.Location, Actual: actual.Location, ErrMsg: fmt.Sprintf("IssueId %s: Component %s:%s Location mismatch", issueId, expected.Name, expected.Version)}, ) if expected.Location != nil { - validatePairs(t, exactMatch, ValidationPair{ Expected: expected.Location.File, Actual: actual.Location.File, ErrMsg: fmt.Sprintf("IssueId %s: Component %s:%s Location.File mismatch", issueId, expected.Name, expected.Version) }) + validatePairs(t, exactMatch, ValidationPair{Expected: expected.Location.File, Actual: actual.Location.File, ErrMsg: fmt.Sprintf("IssueId %s: Component %s:%s Location.File mismatch", issueId, expected.Name, expected.Version)}) } } @@ -187,15 +187,15 @@ func validateCveRows(t *testing.T, issueId string, exactMatch bool, expected, ac } func validateCveRow(t *testing.T, issueId string, exactMatch bool, expected, actual formats.CveRow) { - validatePairs(t, exactMatch, - ValidationPair{ Expected: expected.CvssV2, Actual: actual.CvssV2, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: CvssV2 mismatch", issueId, expected.Id) }, - ValidationPair{ Expected: expected.CvssV3, Actual: actual.CvssV3, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: CvssV3 mismatch", issueId, expected.Id) }, + validatePairs(t, exactMatch, + ValidationPair{Expected: expected.CvssV2, Actual: actual.CvssV2, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: CvssV2 mismatch", issueId, expected.Id)}, + ValidationPair{Expected: expected.CvssV3, Actual: actual.CvssV3, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: CvssV3 mismatch", issueId, expected.Id)}, ) - if validatePairs(t, exactMatch, ValidationPair{ Expected: expected.Applicability, Actual: actual.Applicability, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: Applicability mismatch", issueId, expected.Id) }) && expected.Applicability != nil { - validatePairs(t, exactMatch, - ValidationPair{ Expected: expected.Applicability.Status, Actual: actual.Applicability.Status, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.Status mismatch", issueId, expected.Id) }, - ValidationPair{ Expected: expected.Applicability.ScannerDescription, Actual: actual.Applicability.ScannerDescription, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.ScannerDescription mismatch", issueId, expected.Id) }, - ValidationPair{ Expected: expected.Applicability.Evidence, Actual: actual.Applicability.Evidence, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.Evidence mismatch", issueId, expected.Id) }, + if validatePairs(t, exactMatch, ValidationPair{Expected: expected.Applicability, Actual: actual.Applicability, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: Applicability mismatch", issueId, expected.Id)}) && expected.Applicability != nil { + validatePairs(t, exactMatch, + ValidationPair{Expected: expected.Applicability.Status, Actual: actual.Applicability.Status, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.Status mismatch", issueId, expected.Id)}, + ValidationPair{Expected: expected.Applicability.ScannerDescription, Actual: actual.Applicability.ScannerDescription, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.ScannerDescription mismatch", issueId, expected.Id)}, + ValidationPair{Expected: expected.Applicability.Evidence, Actual: actual.Applicability.Evidence, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.Evidence mismatch", issueId, expected.Id)}, ) } } @@ -209,8 +209,6 @@ func getCve(cve string, content []formats.CveRow) *formats.CveRow { return nil } - - // func VerifySimpleJsonJasResults(t *testing.T, content string, minSastViolations, minIacViolations, minSecrets, // minApplicable, minUndetermined, minNotCovered, minNotApplicable int) { // var results formats.SimpleJsonResults diff --git a/utils/validations/test_validate_summary.go b/utils/validations/test_validate_summary.go index 12694ebf..c1405cc7 100644 --- a/utils/validations/test_validate_summary.go +++ b/utils/validations/test_validate_summary.go @@ -23,4 +23,4 @@ func ValidateCommandSummaryOutput(t *testing.T, params ValidationParams) { // if assert.True(t, ok) { // // // } -} \ No newline at end of file +} diff --git a/utils/validations/test_validate_table.go b/utils/validations/test_validate_table.go index 3a4a5080..7217656b 100644 --- a/utils/validations/test_validate_table.go +++ b/utils/validations/test_validate_table.go @@ -33,4 +33,4 @@ func ValidateCommandTableOutput(t *testing.T, params ValidationParams) { func ValidateTableIssuesCount(t *testing.T, params ValidationParams, results formats.ResultsTables) { -} \ No newline at end of file +} diff --git a/utils/validations/test_validation.go b/utils/validations/test_validation.go index 2deec594..879b0f60 100644 --- a/utils/validations/test_validation.go +++ b/utils/validations/test_validation.go @@ -102,8 +102,6 @@ func validateStrContent(t *testing.T, expected, actual string, actualValue bool, } } - - // func VerifyJsonScanResults(t *testing.T, content string, minViolations, minVulnerabilities, minLicenses int) { // var results []services.ScanResponse // err := json.Unmarshal([]byte(content), &results) @@ -130,4 +128,4 @@ func validateStrContent(t *testing.T, expected, actual string, actualValue bool, // assert.GreaterOrEqual(t, len(results.Vulnerabilities), minVulnerabilities) // assert.GreaterOrEqual(t, len(results.Licenses), minLicenses) // } -// } \ No newline at end of file +// } diff --git a/xsc_test.go b/xsc_test.go index 09bb84d9..e7be50d4 100644 --- a/xsc_test.go +++ b/xsc_test.go @@ -60,7 +60,7 @@ func TestXscAuditNpmJsonWithWatch(t *testing.T) { output := testAuditNpm(t, string(format.Json)) validations.VerifyJsonResults(t, output, validations.ValidationParams{ SecurityViolations: 1, - Licenses: 1, + Licenses: 1, }) } @@ -70,7 +70,7 @@ func TestXscAuditNpmSimpleJsonWithWatch(t *testing.T) { output := testAuditNpm(t, string(format.SimpleJson)) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ SecurityViolations: 1, - Licenses: 1, + Licenses: 1, }) } @@ -80,7 +80,7 @@ func TestXscAuditMavenJson(t *testing.T) { output := testXscAuditMaven(t, string(format.Json)) validations.VerifyJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, - Licenses: 1, + Licenses: 1, }) } @@ -90,7 +90,7 @@ func TestXscAuditMavenSimpleJson(t *testing.T) { output := testXscAuditMaven(t, string(format.SimpleJson)) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, - Licenses: 1, + Licenses: 1, }) } From 382b1cf78148d07810a86507714cd3410f4027a9 Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 14 Jul 2024 18:46:33 +0300 Subject: [PATCH 14/82] some static fixes --- commands/audit/audit.go | 1 - commands/scan/scan.go | 2 +- utils/results/conversion/convertor.go | 4 +++- utils/results/conversion/convertor_test.go | 4 ++-- utils/results/conversion/sarifparser/sarifparser.go | 6 ++++-- utils/results/conversion/summaryparser/summaryparser.go | 4 +++- utils/results/results.go | 4 +--- 7 files changed, 14 insertions(+), 11 deletions(-) diff --git a/commands/audit/audit.go b/commands/audit/audit.go index d1966d5a..846c6264 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -327,5 +327,4 @@ func detectScanTargets(cmdResults *results.SecurityCommandResults, params *Audit } } } - return } diff --git a/commands/scan/scan.go b/commands/scan/scan.go index 8f156e09..cbbff1a0 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -414,7 +414,7 @@ func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, cmdResults } } -func getJasScanner(filePath string, serverDetails *config.ServerDetails, targetResults *results.TargetResults) (*jas.JasScanner, error) { +func getJasScanner(_ string, serverDetails *config.ServerDetails, targetResults *results.TargetResults) (*jas.JasScanner, error) { scanner, err := jas.CreateJasScanner(&jas.JasScanner{}, serverDetails, jas.GetAnalyzerManagerXscEnvVars("", targetResults.GetTechnologies()...)) if err != nil { log.Error(fmt.Sprintf("failed to create jas scanner: %s", err.Error())) diff --git a/utils/results/conversion/convertor.go b/utils/results/conversion/convertor.go index 4e12e2fb..64941699 100644 --- a/utils/results/conversion/convertor.go +++ b/utils/results/conversion/convertor.go @@ -111,7 +111,9 @@ func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormat if c.Params.IsMultipleRoots != nil { multipleTargets = *c.Params.IsMultipleRoots } - parser.Reset(cmdResults.MultiScanId, cmdResults.XrayVersion, jasEntitled) + if err = parser.Reset(cmdResults.MultiScanId, cmdResults.XrayVersion, jasEntitled); err != nil { + return + } for _, targetScansResults := range cmdResults.Targets { if err = parser.ParseNewScanResultsMetadata(targetScansResults.Target, targetScansResults.Errors...); err != nil { return diff --git a/utils/results/conversion/convertor_test.go b/utils/results/conversion/convertor_test.go index 973fec7e..8bf863fe 100644 --- a/utils/results/conversion/convertor_test.go +++ b/utils/results/conversion/convertor_test.go @@ -27,7 +27,7 @@ const ( type conversionFormat string -func getValidationParams(t *testing.T) validations.ValidationParams { +func getValidationParams() validations.ValidationParams { return validations.ValidationParams{ ExactResultsMatch: true, @@ -71,7 +71,7 @@ func TestConvertResults(t *testing.T) { for _, testCase := range testCases { t.Run(fmt.Sprintf("Convert to %s", testCase.contentFormat), func(t *testing.T) { - validationParams := getValidationParams(t) + validationParams := getValidationParams() convertor := NewCommandResultsConvertor(ResultConvertParams{}) switch testCase.contentFormat { diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index db524c66..5c48da1c 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -44,7 +44,9 @@ func (sc *CmdResultsSarifConverter) Get() (*sarif.Report, error) { return sarifutils.NewReport() } // Flush the current run - sc.ParseNewScanResultsMetadata("", nil) + if err := sc.ParseNewScanResultsMetadata("", nil); err != nil { + return sarifutils.NewReport() + } return sc.current, nil } @@ -282,7 +284,7 @@ func addSarifScaLicenseViolation(sarifResults *[]*sarif.Result, rules *map[strin } } -func parseScaToSarifFormat(xrayId, summary, markdownDescription, cveScore string, generateTitleFunc func(depName string, version string, issueId string) string, cves []formats.CveRow, severity severityutils.Severity, applicabilityStatus jasutils.ApplicabilityStatus, impactedPackagesName, impactedPackagesVersion string, fixedVersions []string, directComponents []formats.ComponentRow) (sarifResults []*sarif.Result, rule *sarif.ReportingDescriptor, e error) { +func parseScaToSarifFormat(xrayId, summary, markdownDescription, cveScore string, generateTitleFunc func(depName string, version string, issueId string) string, cves []formats.CveRow, severity severityutils.Severity, _ jasutils.ApplicabilityStatus, impactedPackagesName, impactedPackagesVersion string, fixedVersions []string, directComponents []formats.ComponentRow) (sarifResults []*sarif.Result, rule *sarif.ReportingDescriptor, e error) { issueId := results.GetIssueIdentifier(cves, xrayId, "_") cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, issueId) // Add rule if not exists diff --git a/utils/results/conversion/summaryparser/summaryparser.go b/utils/results/conversion/summaryparser/summaryparser.go index 6d68ddf1..2ba973e4 100644 --- a/utils/results/conversion/summaryparser/summaryparser.go +++ b/utils/results/conversion/summaryparser/summaryparser.go @@ -27,7 +27,9 @@ func (sc *CmdResultsSummaryConverter) Get() *formats.SummaryResults { return &formats.SummaryResults{} } // Flush the last scan - sc.ParseNewScanResultsMetadata("", nil) + if err := sc.ParseNewScanResultsMetadata("", nil); err != nil { + return &formats.SummaryResults{} + } return sc.current } diff --git a/utils/results/results.go b/utils/results/results.go index 38283a98..d3c61e0a 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -167,9 +167,7 @@ func (sr *TargetResults) GetScaScansXrayResults() (results []services.ScanRespon if sr.ScaResults == nil { return } - for _, scaResult := range sr.ScaResults.XrayResults { - results = append(results, scaResult) - } + results = append(results, sr.ScaResults.XrayResults...) return } From 0d46f4f32de4274ca1bdfbce0af6267966c4c9db Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 15 Jul 2024 10:00:18 +0300 Subject: [PATCH 15/82] more static fix --- utils/results/conversion/sarifparser/sarifparser.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index 5c48da1c..137ecf1d 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -284,7 +284,7 @@ func addSarifScaLicenseViolation(sarifResults *[]*sarif.Result, rules *map[strin } } -func parseScaToSarifFormat(xrayId, summary, markdownDescription, cveScore string, generateTitleFunc func(depName string, version string, issueId string) string, cves []formats.CveRow, severity severityutils.Severity, _ jasutils.ApplicabilityStatus, impactedPackagesName, impactedPackagesVersion string, fixedVersions []string, directComponents []formats.ComponentRow) (sarifResults []*sarif.Result, rule *sarif.ReportingDescriptor, e error) { +func parseScaToSarifFormat(xrayId, summary, markdownDescription, cveScore string, generateTitleFunc func(depName string, version string, issueId string) string, cves []formats.CveRow, severity severityutils.Severity, _ jasutils.ApplicabilityStatus, impactedPackagesName, impactedPackagesVersion string, _ []string, directComponents []formats.ComponentRow) (sarifResults []*sarif.Result, rule *sarif.ReportingDescriptor, e error) { issueId := results.GetIssueIdentifier(cves, xrayId, "_") cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, issueId) // Add rule if not exists From 47e7f5f0c335f725c5474204a0831641548249cb Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 15 Jul 2024 11:11:57 +0300 Subject: [PATCH 16/82] fix static --- utils/validations/test_validation.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/utils/validations/test_validation.go b/utils/validations/test_validation.go index 879b0f60..092f16e1 100644 --- a/utils/validations/test_validation.go +++ b/utils/validations/test_validation.go @@ -57,25 +57,29 @@ func (vp ValidationPair) ErrMsgs(t *testing.T) []string { func validatePairs(t *testing.T, exactMatch bool, pairs ...ValidationPair) bool { for _, pair := range pairs { - switch pair.Expected.(type) { + switch expected := pair.Expected.(type) { case string: - if !validateStrContent(t, pair.Expected.(string), pair.Actual.(string), exactMatch, pair.ErrMsgs(t)) { + actual, ok := pair.Actual.(string) + if !ok { + return assert.Fail(t, "Expected a string value, but got a different type.", pair.ErrMsgs(t)) + } + if !validateStrContent(t, expected, actual, exactMatch, pair.ErrMsgs(t)) { return false } case *interface{}: - if !validatePointers(t, pair.Expected, pair.Actual, exactMatch, pair.ErrMsgs(t)) { + if !validatePointers(t, expected, pair.Actual, exactMatch, pair.ErrMsgs(t)) { return false } case []interface{}: if exactMatch { - if !assert.ElementsMatch(t, pair.Expected, pair.Actual, pair.ErrMsgs(t)) { + if !assert.ElementsMatch(t, expected, pair.Actual, pair.ErrMsgs(t)) { return false } - } else if !assert.Subset(t, pair.Expected, pair.Actual, pair.ErrMsgs(t)) { + } else if !assert.Subset(t, expected, pair.Actual, pair.ErrMsgs(t)) { return false } default: - return assert.Equal(t, pair.Expected, pair.Actual, pair.ErrMsgs(t)) + return assert.Equal(t, expected, pair.Actual, pair.ErrMsgs(t)) } } return true From 3c9c41dbcb85e69753f62981555a2f7e266b6153 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 15 Jul 2024 11:15:09 +0300 Subject: [PATCH 17/82] fix static --- .../conversion/sarifparser/sarifparser.go | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index 137ecf1d..01186198 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -209,10 +209,7 @@ func addSarifScaVulnerability(sarifResults *[]*sarif.Result, rules *map[string]* if err != nil { return err } - currentResults, currentRule, err := parseScaToSarifFormat(vulnerability.IssueId, vulnerability.Summary, markdownDescription, maxCveScore, getScaIssueSarifHeadline, cves, severity, applicabilityStatus, impactedPackagesName, impactedPackagesVersion, fixedVersions, directComponents) - if err != nil { - return err - } + currentResults, currentRule := parseScaToSarifFormat(vulnerability.IssueId, vulnerability.Summary, markdownDescription, maxCveScore, getScaIssueSarifHeadline, cves, severity, applicabilityStatus, impactedPackagesName, impactedPackagesVersion, fixedVersions, directComponents) cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, results.GetIssueIdentifier(cves, vulnerability.IssueId, "_")) if _, ok := (*rules)[cveImpactedComponentRuleId]; !ok { // New Rule @@ -233,10 +230,7 @@ func addSarifScaSecurityViolation(sarifResults *[]*sarif.Result, rules *map[stri if err != nil { return err } - currentResults, currentRule, err := parseScaToSarifFormat(violation.IssueId, violation.Summary, markdownDescription, maxCveScore, getScaIssueSarifHeadline, cves, severity, applicabilityStatus, impactedPackagesName, impactedPackagesVersion, fixedVersions, directComponents) - if err != nil { - return err - } + currentResults, currentRule := parseScaToSarifFormat(violation.IssueId, violation.Summary, markdownDescription, maxCveScore, getScaIssueSarifHeadline, cves, severity, applicabilityStatus, impactedPackagesName, impactedPackagesVersion, fixedVersions, directComponents) cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, results.GetIssueIdentifier(cves, violation.IssueId, "_")) if _, ok := (*rules)[cveImpactedComponentRuleId]; !ok { // New Rule @@ -257,7 +251,7 @@ func addSarifScaLicenseViolation(sarifResults *[]*sarif.Result, rules *map[strin if err != nil { return err } - currentResults, currentRule, err := parseScaToSarifFormat( + currentResults, currentRule := parseScaToSarifFormat( violation.LicenseKey, getLicenseViolationSummary(impactedPackagesName, impactedPackagesVersion, violation.LicenseKey), markdownDescription, @@ -271,9 +265,6 @@ func addSarifScaLicenseViolation(sarifResults *[]*sarif.Result, rules *map[strin fixedVersions, directComponents, ) - if err != nil { - return err - } cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, results.GetIssueIdentifier(cves, violation.LicenseKey, "_")) if _, ok := (*rules)[cveImpactedComponentRuleId]; !ok { // New Rule @@ -284,7 +275,7 @@ func addSarifScaLicenseViolation(sarifResults *[]*sarif.Result, rules *map[strin } } -func parseScaToSarifFormat(xrayId, summary, markdownDescription, cveScore string, generateTitleFunc func(depName string, version string, issueId string) string, cves []formats.CveRow, severity severityutils.Severity, _ jasutils.ApplicabilityStatus, impactedPackagesName, impactedPackagesVersion string, _ []string, directComponents []formats.ComponentRow) (sarifResults []*sarif.Result, rule *sarif.ReportingDescriptor, e error) { +func parseScaToSarifFormat(xrayId, summary, markdownDescription, cveScore string, generateTitleFunc func(depName string, version string, issueId string) string, cves []formats.CveRow, severity severityutils.Severity, _ jasutils.ApplicabilityStatus, impactedPackagesName, impactedPackagesVersion string, _ []string, directComponents []formats.ComponentRow) (sarifResults []*sarif.Result, rule *sarif.ReportingDescriptor) { issueId := results.GetIssueIdentifier(cves, xrayId, "_") cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, issueId) // Add rule if not exists From 2523009c2defc6b964f146f3014e5c6b3bf77f34 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 15 Jul 2024 11:38:37 +0300 Subject: [PATCH 18/82] fix race condition --- utils/results/results.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/results/results.go b/utils/results/results.go index d3c61e0a..e95825f5 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -112,7 +112,9 @@ func (r *SecurityCommandResults) GetErrors() (err error) { func (r *SecurityCommandResults) GetTechnologies() []techutils.Technology { technologies := datastructures.MakeSet[techutils.Technology]() for _, scan := range r.Targets { + r.targetsMutex.Lock() technologies.AddElements(scan.GetTechnologies()...) + r.targetsMutex.Unlock() } return technologies.ToSlice() } From b368f1c299559e858feb6a26317405fe3fecda22 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 15 Jul 2024 12:17:39 +0300 Subject: [PATCH 19/82] start sarif --- utils/formats/conversion.go | 6 +++--- utils/formats/table.go | 4 ++-- utils/validations/test_validate_table.go | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/utils/formats/conversion.go b/utils/formats/conversion.go index 6ec0764a..a5e31068 100644 --- a/utils/formats/conversion.go +++ b/utils/formats/conversion.go @@ -5,7 +5,7 @@ import ( "strings" ) -func ConvertSecurityTableRowToScanTableRow(tableRows []VulnerabilityTableRow) (scanTableRows []vulnerabilityScanTableRow) { +func ConvertSecurityTableRowToScanTableRow(tableRows []vulnerabilityTableRow) (scanTableRows []vulnerabilityScanTableRow) { for i := range tableRows { scanTableRows = append(scanTableRows, vulnerabilityScanTableRow{ severity: tableRows[i].severity, @@ -83,9 +83,9 @@ func convertToComponentScanTableRow(rows []directDependenciesTableRow) (tableRow return } -func ConvertToVulnerabilityTableRow(rows []VulnerabilityOrViolationRow) (tableRows []VulnerabilityTableRow) { +func ConvertToVulnerabilityTableRow(rows []VulnerabilityOrViolationRow) (tableRows []vulnerabilityTableRow) { for i := range rows { - tableRows = append(tableRows, VulnerabilityTableRow{ + tableRows = append(tableRows, vulnerabilityTableRow{ severity: rows[i].Severity, severityNumValue: rows[i].SeverityNumValue, applicable: rows[i].Applicable, diff --git a/utils/formats/table.go b/utils/formats/table.go index 23704767..29e8f41f 100644 --- a/utils/formats/table.go +++ b/utils/formats/table.go @@ -5,7 +5,7 @@ package formats // Use the conversion methods in this package to convert from the API structs to the table structs. type ResultsTables struct { - SecurityVulnerabilitiesTable []VulnerabilityTableRow + SecurityVulnerabilitiesTable []vulnerabilityTableRow LicensesTable []licenseTableRow LicenseViolationsTable []licenseViolationTableRow OperationalRiskViolationsTable []operationalRiskViolationTableRow @@ -16,7 +16,7 @@ type ResultsTables struct { } // Used for vulnerabilities and security violations -type VulnerabilityTableRow struct { +type vulnerabilityTableRow struct { severity string `col-name:"Severity"` applicable string `col-name:"Contextual\nAnalysis" omitempty:"true"` // For sorting diff --git a/utils/validations/test_validate_table.go b/utils/validations/test_validate_table.go index 7217656b..b716b7c2 100644 --- a/utils/validations/test_validate_table.go +++ b/utils/validations/test_validate_table.go @@ -2,6 +2,7 @@ package validations import ( "encoding/json" + "fmt" "testing" "github.com/jfrog/jfrog-cli-security/utils/formats" @@ -33,4 +34,21 @@ func ValidateCommandTableOutput(t *testing.T, params ValidationParams) { func ValidateTableIssuesCount(t *testing.T, params ValidationParams, results formats.ResultsTables) { + if params.ExactResultsMatch { + assert.Len(t, results.SastTable, params.Sast, fmt.Sprintf("Expected %d sast issues in table, but got %d sast.", params.Sast, len(results.SastTable))) + assert.Len(t, results.SecretsTable, params.Secrets, fmt.Sprintf("Expected %d secrets issues in table, but got %d secrets.", params.Secrets, len(results.SecretsTable))) + assert.Len(t, results.IacTable, params.Iac, fmt.Sprintf("Expected %d IaC issues in table, but got %d IaC.", params.Iac, len(results.IacTable))) + assert.Len(t, results.LicenseViolationsTable, params.LicenseViolations, fmt.Sprintf("Expected %d license issues in table, but got %d license issues.", params.Licenses, len(results.LicenseViolationsTable))) + assert.Len(t, results.LicensesTable, params.Licenses, fmt.Sprintf("Expected %d licenses in table, but got %d licenses.", params.Licenses, len(results.LicensesTable))) + assert.Len(t, results.OperationalRiskViolationsTable, params.OperationalViolations, fmt.Sprintf("Expected %d operational risk issues in table, but got %d operational risk issues.", params.OperationalViolations, len(results.OperationalRiskViolationsTable))) + assert.Equal(t, params.Vulnerabilities+params.SecurityViolations, len(results.SecurityVulnerabilitiesTable), fmt.Sprintf("Expected %d vulnerabilities in table, but got %d vulnerabilities.", params.Vulnerabilities, len(results.SecurityVulnerabilitiesTable))) + return + } + assert.GreaterOrEqual(t, len(results.SastTable), params.Sast, fmt.Sprintf("Expected at least %d sast issues in table, but got %d sast.", params.Sast, len(results.SastTable))) + assert.GreaterOrEqual(t, len(results.SecretsTable), params.Secrets, fmt.Sprintf("Expected at least %d secrets issues in table, but got %d secrets.", params.Secrets, len(results.SecretsTable))) + assert.GreaterOrEqual(t, len(results.IacTable), params.Iac, fmt.Sprintf("Expected at least %d IaC issues in table, but got %d IaC.", params.Iac, len(results.IacTable))) + assert.GreaterOrEqual(t, len(results.LicenseViolationsTable), params.LicenseViolations, fmt.Sprintf("Expected at least %d license issues in table, but got %d license issues.", params.Licenses, len(results.LicenseViolationsTable))) + assert.GreaterOrEqual(t, len(results.LicensesTable), params.Licenses, fmt.Sprintf("Expected at least %d licenses in table, but got %d licenses.", params.Licenses, len(results.LicensesTable))) + assert.GreaterOrEqual(t, len(results.OperationalRiskViolationsTable), params.OperationalViolations, fmt.Sprintf("Expected at least %d operational risk issues in table, but got %d operational risk issues.", params.OperationalViolations, len(results.OperationalRiskViolationsTable))) + assert.GreaterOrEqual(t, len(results.SecurityVulnerabilitiesTable), params.Vulnerabilities+params.SecurityViolations, fmt.Sprintf("Expected at least %d vulnerabilities in table, but got %d vulnerabilities.", params.Vulnerabilities, len(results.SecurityVulnerabilitiesTable))) } From cb0ff0211880670cf56ae44d9fd7336263cc0555 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 15 Jul 2024 15:39:00 +0300 Subject: [PATCH 20/82] fix parallel race --- utils/results/results.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/utils/results/results.go b/utils/results/results.go index e95825f5..e2aa396f 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -40,6 +40,7 @@ type TargetResults struct { // All scan results for the target ScaResults *ScaScanResults `json:"sca_scans,omitempty"` JasResults *JasScansResults `json:"jas_scans,omitempty"` + scansMutex sync.Mutex `json:"-"` // Errors that occurred during the scans Errors []error `json:"errors,omitempty"` errorsMutex sync.Mutex `json:"-"` @@ -111,11 +112,11 @@ func (r *SecurityCommandResults) GetErrors() (err error) { func (r *SecurityCommandResults) GetTechnologies() []techutils.Technology { technologies := datastructures.MakeSet[techutils.Technology]() + r.targetsMutex.Lock() for _, scan := range r.Targets { - r.targetsMutex.Lock() technologies.AddElements(scan.GetTechnologies()...) - r.targetsMutex.Unlock() } + r.targetsMutex.Unlock() return technologies.ToSlice() } @@ -178,6 +179,7 @@ func (sr *TargetResults) GetTechnologies() []techutils.Technology { if sr.Technology != "" { technologiesSet.Add(sr.Technology) } + sr.scansMutex.Lock() if sr.ScaResults == nil { return technologiesSet.ToSlice() } @@ -186,6 +188,7 @@ func (sr *TargetResults) GetTechnologies() []techutils.Technology { technologiesSet.Add(techutils.Technology(strings.ToLower(scaResult.ScannedPackageType))) } } + sr.scansMutex.Unlock() return technologiesSet.ToSlice() } @@ -232,10 +235,12 @@ func (sr *TargetResults) SetDescriptors(descriptors ...string) *TargetResults { func (sr *TargetResults) NewScaScanResults(responses ...services.ScanResponse) *ScaScanResults { results := sr.ScaResults + sr.scansMutex.Lock() if results == nil { results = &ScaScanResults{} sr.ScaResults = results } + sr.scansMutex.Unlock() results.XrayResults = append(results.XrayResults, responses...) return results } From 8736ca63a01a5a4981a2cebac689d0d95869aaf6 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 15 Jul 2024 15:39:21 +0300 Subject: [PATCH 21/82] fix test data location --- utils/results/conversion/convertor_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/results/conversion/convertor_test.go b/utils/results/conversion/convertor_test.go index 8bf863fe..31dcf456 100644 --- a/utils/results/conversion/convertor_test.go +++ b/utils/results/conversion/convertor_test.go @@ -15,7 +15,7 @@ import ( ) var ( - testDataDir = filepath.Join("..", "..", "..", "testdata", "other", "output", "formats") + testDataDir = filepath.Join("..", "..", "..", "tests", "testdata", "other", "output", "formats") ) const ( From 7eeb1e727868f58b67bf3380c87ca0f08bfe8c66 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 15 Jul 2024 16:19:33 +0300 Subject: [PATCH 22/82] continue implement --- .../simplejsonparser/simplejsonparser.go | 1 - .../validations/test_validate_simple_json.go | 28 +++---- utils/validations/test_validate_summary.go | 78 +++++++++++++++++-- utils/validations/test_validate_table.go | 7 -- utils/validations/test_validation.go | 30 +------ 5 files changed, 88 insertions(+), 56 deletions(-) diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go index 68544e23..118ddfea 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go @@ -396,7 +396,6 @@ func getJfrogResearchPriority(vulnerabilityOrViolation formats.VulnerabilityOrVi if vulnerabilityOrViolation.JfrogResearchInformation == nil { return vulnerabilityOrViolation.SeverityNumValue } - return vulnerabilityOrViolation.JfrogResearchInformation.SeverityNumValue } diff --git a/utils/validations/test_validate_simple_json.go b/utils/validations/test_validate_simple_json.go index 1c8408eb..93f4ae56 100644 --- a/utils/validations/test_validate_simple_json.go +++ b/utils/validations/test_validate_simple_json.go @@ -49,7 +49,7 @@ func ValidateSimpleJsonIssuesCount(t *testing.T, params ValidationParams, result } if params.ExactResultsMatch { - assert.Equal(t, params.Sast, len(results.Sast), "Expected %d sast in scan responses, but got %d sast.", params.Sast, len(results.Sast)) + assert.Equal(t, params.Sast, len(results.Sast), "Expected %d sast in scan responses, but got %d sast.", params.Sast, len(results.Sast)) assert.Equal(t, params.Secrets, len(results.Secrets), "Expected %d secrets in scan responses, but got %d secrets.", params.Secrets, len(results.Secrets)) assert.Equal(t, params.Iac, len(results.Iacs), "Expected %d IaC in scan responses, but got %d IaC.", params.Iac, len(results.Iacs)) @@ -63,22 +63,22 @@ func ValidateSimpleJsonIssuesCount(t *testing.T, params ValidationParams, result assert.Equal(t, params.OperationalViolations, len(results.OperationalRiskViolations), "Expected %d operational risk violations in scan responses, but got %d operational risk violations.", params.OperationalViolations, len(results.OperationalRiskViolations)) assert.Equal(t, params.Licenses, len(results.Licenses), "Expected %d Licenses in scan responses, but got %d Licenses.", params.Licenses, len(results.Licenses)) - } else { - assert.GreaterOrEqual(t, len(results.Sast), params.Sast, "Expected at least %d sast in scan responses, but got %d sast.", params.Sast, len(results.Sast)) - assert.GreaterOrEqual(t, len(results.Secrets), params.Secrets, "Expected at least %d secrets in scan responses, but got %d secrets.", params.Secrets, len(results.Secrets)) - assert.GreaterOrEqual(t, len(results.Iacs), params.Iac, "Expected at least %d IaC in scan responses, but got %d IaC.", params.Iac, len(results.Iacs)) + return + } + assert.GreaterOrEqual(t, len(results.Sast), params.Sast, "Expected at least %d sast in scan responses, but got %d sast.", params.Sast, len(results.Sast)) + assert.GreaterOrEqual(t, len(results.Secrets), params.Secrets, "Expected at least %d secrets in scan responses, but got %d secrets.", params.Secrets, len(results.Secrets)) + assert.GreaterOrEqual(t, len(results.Iacs), params.Iac, "Expected at least %d IaC in scan responses, but got %d IaC.", params.Iac, len(results.Iacs)) - assert.GreaterOrEqual(t, applicableResults, params.Applicable, "Expected at least %d applicable vulnerabilities in scan responses, but got %d applicable vulnerabilities.", params.Applicable, applicableResults) - assert.GreaterOrEqual(t, undeterminedResults, params.Undetermined, "Expected at least %d undetermined vulnerabilities in scan responses, but got %d undetermined vulnerabilities.", params.Undetermined, undeterminedResults) - assert.GreaterOrEqual(t, notCoveredResults, params.NotCovered, "Expected at least %d not covered vulnerabilities in scan responses, but got %d not covered vulnerabilities.", params.NotCovered, notCoveredResults) - assert.GreaterOrEqual(t, notApplicableResults, params.NotApplicable, "Expected at least %d not applicable vulnerabilities in scan responses, but got %d not applicable vulnerabilities.", params.NotApplicable, notApplicableResults) + assert.GreaterOrEqual(t, applicableResults, params.Applicable, "Expected at least %d applicable vulnerabilities in scan responses, but got %d applicable vulnerabilities.", params.Applicable, applicableResults) + assert.GreaterOrEqual(t, undeterminedResults, params.Undetermined, "Expected at least %d undetermined vulnerabilities in scan responses, but got %d undetermined vulnerabilities.", params.Undetermined, undeterminedResults) + assert.GreaterOrEqual(t, notCoveredResults, params.NotCovered, "Expected at least %d not covered vulnerabilities in scan responses, but got %d not covered vulnerabilities.", params.NotCovered, notCoveredResults) + assert.GreaterOrEqual(t, notApplicableResults, params.NotApplicable, "Expected at least %d not applicable vulnerabilities in scan responses, but got %d not applicable vulnerabilities.", params.NotApplicable, notApplicableResults) - assert.GreaterOrEqual(t, len(results.SecurityViolations), params.SecurityViolations, "Expected at least %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, len(results.SecurityViolations)) - assert.GreaterOrEqual(t, len(results.LicensesViolations), params.LicenseViolations, "Expected at least %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, len(results.LicensesViolations)) - assert.GreaterOrEqual(t, len(results.OperationalRiskViolations), params.OperationalViolations, "Expected at least %d operational risk violations in scan responses, but got %d operational risk violations.", params.OperationalViolations, len(results.OperationalRiskViolations)) + assert.GreaterOrEqual(t, len(results.SecurityViolations), params.SecurityViolations, "Expected at least %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, len(results.SecurityViolations)) + assert.GreaterOrEqual(t, len(results.LicensesViolations), params.LicenseViolations, "Expected at least %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, len(results.LicensesViolations)) + assert.GreaterOrEqual(t, len(results.OperationalRiskViolations), params.OperationalViolations, "Expected at least %d operational risk violations in scan responses, but got %d operational risk violations.", params.OperationalViolations, len(results.OperationalRiskViolations)) - assert.GreaterOrEqual(t, len(results.Licenses), params.Licenses, "Expected at least %d Licenses in scan responses, but got %d Licenses.", params.Licenses, len(results.Licenses)) - } + assert.GreaterOrEqual(t, len(results.Licenses), params.Licenses, "Expected at least %d Licenses in scan responses, but got %d Licenses.", params.Licenses, len(results.Licenses)) } func ValidateSimpleJsonResults(t *testing.T, exactMatch bool, expected, actual formats.SimpleJsonResults) { diff --git a/utils/validations/test_validate_summary.go b/utils/validations/test_validate_summary.go index c1405cc7..d95afa68 100644 --- a/utils/validations/test_validate_summary.go +++ b/utils/validations/test_validate_summary.go @@ -5,10 +5,11 @@ import ( "testing" "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/stretchr/testify/assert" ) -// Content should be a Json string of formats.ResultsTables and will be unmarshal. +// Content should be a Json string of formats.SummaryResults and will be unmarshal. // Value is set as the Actual content in the validation params func VerifySummaryResults(t *testing.T, content string, params ValidationParams) { var results formats.SummaryResults @@ -19,8 +20,75 @@ func VerifySummaryResults(t *testing.T, content string, params ValidationParams) } func ValidateCommandSummaryOutput(t *testing.T, params ValidationParams) { - // results, ok := params.Actual.(formats.ResultsTables) - // if assert.True(t, ok) { - // // - // } + results, ok := params.Actual.(formats.SummaryResults) + if assert.True(t, ok) { + ValidateSummaryIssuesCount(t, params, results) + } +} + +func ValidateSummaryIssuesCount(t *testing.T, params ValidationParams, results formats.SummaryResults) { + var vulnerabilities, securityViolations, licenseViolations, opRiskViolations, applicableResults, undeterminedResults, notCoveredResults, notApplicableResults, sast, iac, secrets int + for _, scan := range results.Scans { + // Vulnerabilities + if scan.Vulnerabilities != nil { + if scan.Vulnerabilities.ScaScanResults != nil { + vulnerabilities += scan.Vulnerabilities.ScaScanResults.SummaryCount.GetTotal() + for _, counts := range scan.Vulnerabilities.ScaScanResults.SummaryCount { + for status, count := range counts { + switch status { + case jasutils.Applicable.String(): + applicableResults += count + case jasutils.ApplicabilityUndetermined.String(): + undeterminedResults += count + case jasutils.NotCovered.String(): + notCoveredResults += count + case jasutils.NotApplicable.String(): + notApplicableResults += count + } + } + } + } + if scan.Vulnerabilities.SastScanResults != nil { + sast += scan.Vulnerabilities.SastScanResults.GetTotal() + } + if scan.Vulnerabilities.SecretsScanResults != nil { + secrets += scan.Vulnerabilities.SecretsScanResults.GetTotal() + } + if scan.Vulnerabilities.IacScanResults != nil { + iac += scan.Vulnerabilities.IacScanResults.GetTotal() + } + } + // Violations + securityViolations += scan.Violations[formats.ViolationTypeSecurity.String()].GetTotal() + licenseViolations += scan.Violations[formats.ViolationTypeLicense.String()].GetTotal() + opRiskViolations += scan.Violations[formats.ViolationTypeOperationalRisk.String()].GetTotal() + } + + if params.ExactResultsMatch { + assert.Equal(t, params.Sast, sast, "Expected %d sast in scan responses, but got %d sast.", params.Sast, sast) + assert.Equal(t, params.Secrets, secrets, "Expected %d secrets in scan responses, but got %d secrets.", params.Secrets, secrets) + assert.Equal(t, params.Iac, iac, "Expected %d IaC in scan responses, but got %d IaC.", params.Iac, iac) + + assert.Equal(t, params.Applicable, applicableResults, "Expected %d applicable vulnerabilities in scan responses, but got %d applicable vulnerabilities.", params.Applicable, applicableResults) + assert.Equal(t, params.Undetermined, undeterminedResults, "Expected %d undetermined vulnerabilities in scan responses, but got %d undetermined vulnerabilities.", params.Undetermined, undeterminedResults) + assert.Equal(t, params.NotCovered, notCoveredResults, "Expected %d not covered vulnerabilities in scan responses, but got %d not covered vulnerabilities.", params.NotCovered, notCoveredResults) + assert.Equal(t, params.NotApplicable, notApplicableResults, "Expected %d not applicable vulnerabilities in scan responses, but got %d not applicable vulnerabilities.", params.NotApplicable, notApplicableResults) + + assert.Equal(t, params.SecurityViolations, securityViolations, "Expected %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, securityViolations) + assert.Equal(t, params.LicenseViolations, licenseViolations, "Expected %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, licenseViolations) + assert.Equal(t, params.OperationalViolations, opRiskViolations, "Expected %d operational risk violations in scan responses, but got %d operational risk violations.", params.OperationalViolations, opRiskViolations) + return + } + assert.GreaterOrEqual(t, sast, params.Sast, "Expected at least %d sast in scan responses, but got %d sast.", params.Sast, sast) + assert.GreaterOrEqual(t, secrets, params.Secrets, "Expected at least %d secrets in scan responses, but got %d secrets.", params.Secrets, secrets) + assert.GreaterOrEqual(t, iac, params.Iac, "Expected at least %d IaC in scan responses, but got %d IaC.", params.Iac, iac) + + assert.GreaterOrEqual(t, applicableResults, params.Applicable, "Expected at least %d applicable vulnerabilities in scan responses, but got %d applicable vulnerabilities.", params.Applicable, applicableResults) + assert.GreaterOrEqual(t, undeterminedResults, params.Undetermined, "Expected at least %d undetermined vulnerabilities in scan responses, but got %d undetermined vulnerabilities.", params.Undetermined, undeterminedResults) + assert.GreaterOrEqual(t, notCoveredResults, params.NotCovered, "Expected at least %d not covered vulnerabilities in scan responses, but got %d not covered vulnerabilities.", params.NotCovered, notCoveredResults) + assert.GreaterOrEqual(t, notApplicableResults, params.NotApplicable, "Expected at least %d not applicable vulnerabilities in scan responses, but got %d not applicable vulnerabilities.", params.NotApplicable, notApplicableResults) + + assert.GreaterOrEqual(t, securityViolations, params.SecurityViolations, "Expected at least %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, securityViolations) + assert.GreaterOrEqual(t, licenseViolations, params.LicenseViolations, "Expected at least %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, licenseViolations) + assert.GreaterOrEqual(t, securityViolations, params.OperationalViolations, "Expected at least %d operational risk violations in scan responses, but got %d operational risk violations.", params.OperationalViolations, opRiskViolations) } diff --git a/utils/validations/test_validate_table.go b/utils/validations/test_validate_table.go index b716b7c2..131f1d7d 100644 --- a/utils/validations/test_validate_table.go +++ b/utils/validations/test_validate_table.go @@ -23,17 +23,10 @@ func ValidateCommandTableOutput(t *testing.T, params ValidationParams) { results, ok := params.Actual.(formats.ResultsTables) if assert.True(t, ok) { ValidateTableIssuesCount(t, params, results) - // if params.Expected != nil { - // expectedResults, ok := params.Expected.(sarif.Report) - // if assert.True(t, ok) { - // ValidateScanResponses(t, params.ExactResultsMatch, expectedResults, results) - // } - // } } } func ValidateTableIssuesCount(t *testing.T, params ValidationParams, results formats.ResultsTables) { - if params.ExactResultsMatch { assert.Len(t, results.SastTable, params.Sast, fmt.Sprintf("Expected %d sast issues in table, but got %d sast.", params.Sast, len(results.SastTable))) assert.Len(t, results.SecretsTable, params.Secrets, fmt.Sprintf("Expected %d secrets issues in table, but got %d secrets.", params.Secrets, len(results.SecretsTable))) diff --git a/utils/validations/test_validation.go b/utils/validations/test_validation.go index 092f16e1..a0ddb3ff 100644 --- a/utils/validations/test_validation.go +++ b/utils/validations/test_validation.go @@ -104,32 +104,4 @@ func validateStrContent(t *testing.T, expected, actual string, actualValue bool, } else { return assert.Empty(t, actual, msgAndArgs...) } -} - -// func VerifyJsonScanResults(t *testing.T, content string, minViolations, minVulnerabilities, minLicenses int) { -// var results []services.ScanResponse -// err := json.Unmarshal([]byte(content), &results) -// if assert.NoError(t, err) { -// var violations []services.Violation -// var vulnerabilities []services.Vulnerability -// var licenses []services.License -// for _, result := range results { -// violations = append(violations, result.Violations...) -// vulnerabilities = append(vulnerabilities, result.Vulnerabilities...) -// licenses = append(licenses, result.Licenses...) -// } -// assert.True(t, len(violations) >= minViolations, fmt.Sprintf("Expected at least %d violations in scan results, but got %d violations.", minViolations, len(violations))) -// assert.True(t, len(vulnerabilities) >= minVulnerabilities, fmt.Sprintf("Expected at least %d vulnerabilities in scan results, but got %d vulnerabilities.", minVulnerabilities, len(vulnerabilities))) -// assert.True(t, len(licenses) >= minLicenses, fmt.Sprintf("Expected at least %d Licenses in scan results, but got %d Licenses.", minLicenses, len(licenses))) -// } -// } - -// func VerifySimpleJsonScanResults(t *testing.T, content string, minViolations, minVulnerabilities, minLicenses int) { -// var results formats.SimpleJsonResults -// err := json.Unmarshal([]byte(content), &results) -// if assert.NoError(t, err) { -// assert.GreaterOrEqual(t, len(results.SecurityViolations), minViolations) -// assert.GreaterOrEqual(t, len(results.Vulnerabilities), minVulnerabilities) -// assert.GreaterOrEqual(t, len(results.Licenses), minLicenses) -// } -// } +} \ No newline at end of file From 18015b6325bb0cf4f8131eda0d49f82a0246abc0 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 15 Jul 2024 18:40:59 +0300 Subject: [PATCH 23/82] fix tests --- commands/audit/audit.go | 2 ++ utils/results/results.go | 11 ++--------- utils/validations/test_validate_simple_json.go | 2 +- utils/validations/test_validation.go | 2 +- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/commands/audit/audit.go b/commands/audit/audit.go index 846c6264..292969b2 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -267,7 +267,9 @@ func downloadAnalyzerManagerAndRunScanners(auditParallelRunner *utils.SecurityPa if err = jas.DownloadAnalyzerManagerIfNeeded(threadId); err != nil { return fmt.Errorf("%s failed to download analyzer manager: %s", clientutils.GetLogMsgPrefix(threadId, false), err.Error()) } + auditParallelRunner.ResultsMu.Lock() scanner, err = jas.CreateJasScanner(scanner, serverDetails, jas.GetAnalyzerManagerXscEnvVars(auditParams.commonGraphScanParams.MultiScanId, scanResults.GetTechnologies()...), auditParams.Exclusions()...) + auditParallelRunner.ResultsMu.Unlock() if err != nil { return fmt.Errorf("failed to create jas scanner: %s", err.Error()) } diff --git a/utils/results/results.go b/utils/results/results.go index e2aa396f..f06916e0 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -40,7 +40,6 @@ type TargetResults struct { // All scan results for the target ScaResults *ScaScanResults `json:"sca_scans,omitempty"` JasResults *JasScansResults `json:"jas_scans,omitempty"` - scansMutex sync.Mutex `json:"-"` // Errors that occurred during the scans Errors []error `json:"errors,omitempty"` errorsMutex sync.Mutex `json:"-"` @@ -112,11 +111,9 @@ func (r *SecurityCommandResults) GetErrors() (err error) { func (r *SecurityCommandResults) GetTechnologies() []techutils.Technology { technologies := datastructures.MakeSet[techutils.Technology]() - r.targetsMutex.Lock() for _, scan := range r.Targets { technologies.AddElements(scan.GetTechnologies()...) } - r.targetsMutex.Unlock() return technologies.ToSlice() } @@ -179,7 +176,6 @@ func (sr *TargetResults) GetTechnologies() []techutils.Technology { if sr.Technology != "" { technologiesSet.Add(sr.Technology) } - sr.scansMutex.Lock() if sr.ScaResults == nil { return technologiesSet.ToSlice() } @@ -188,7 +184,6 @@ func (sr *TargetResults) GetTechnologies() []techutils.Technology { technologiesSet.Add(techutils.Technology(strings.ToLower(scaResult.ScannedPackageType))) } } - sr.scansMutex.Unlock() return technologiesSet.ToSlice() } @@ -235,14 +230,12 @@ func (sr *TargetResults) SetDescriptors(descriptors ...string) *TargetResults { func (sr *TargetResults) NewScaScanResults(responses ...services.ScanResponse) *ScaScanResults { results := sr.ScaResults - sr.scansMutex.Lock() if results == nil { results = &ScaScanResults{} sr.ScaResults = results } - sr.scansMutex.Unlock() - results.XrayResults = append(results.XrayResults, responses...) - return results + sr.ScaResults.XrayResults = append(results.XrayResults, responses...) + return sr.ScaResults } func (ssr *ScaScanResults) HasInformation() bool { diff --git a/utils/validations/test_validate_simple_json.go b/utils/validations/test_validate_simple_json.go index 93f4ae56..fdb2e1b2 100644 --- a/utils/validations/test_validate_simple_json.go +++ b/utils/validations/test_validate_simple_json.go @@ -49,7 +49,7 @@ func ValidateSimpleJsonIssuesCount(t *testing.T, params ValidationParams, result } if params.ExactResultsMatch { - assert.Equal(t, params.Sast, len(results.Sast), "Expected %d sast in scan responses, but got %d sast.", params.Sast, len(results.Sast)) + assert.Equal(t, params.Sast, len(results.Sast), "Expected %d sast in scan responses, but got %d sast.", params.Sast, len(results.Sast)) assert.Equal(t, params.Secrets, len(results.Secrets), "Expected %d secrets in scan responses, but got %d secrets.", params.Secrets, len(results.Secrets)) assert.Equal(t, params.Iac, len(results.Iacs), "Expected %d IaC in scan responses, but got %d IaC.", params.Iac, len(results.Iacs)) diff --git a/utils/validations/test_validation.go b/utils/validations/test_validation.go index a0ddb3ff..755cb372 100644 --- a/utils/validations/test_validation.go +++ b/utils/validations/test_validation.go @@ -104,4 +104,4 @@ func validateStrContent(t *testing.T, expected, actual string, actualValue bool, } else { return assert.Empty(t, actual, msgAndArgs...) } -} \ No newline at end of file +} From 7241b86955a8293349ee5eb440b9001baf34b834 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 16 Jul 2024 15:34:34 +0300 Subject: [PATCH 24/82] fix tests --- .../other/output/formats/audit_results.json | 1 + .../output/formats/audit_simple_json.json | 1650 +++++++++-------- .../other/output/formats/audit_summary.json | 36 + utils/results/common.go | 3 + utils/results/common_test.go | 227 +-- utils/results/conversion/convertor_test.go | 25 +- utils/validations/test_validate_summary.go | 2 +- utils/validations/test_validate_table.go | 47 - 8 files changed, 924 insertions(+), 1067 deletions(-) delete mode 100644 utils/validations/test_validate_table.go diff --git a/tests/testdata/other/output/formats/audit_results.json b/tests/testdata/other/output/formats/audit_results.json index 1c71d750..7167996d 100644 --- a/tests/testdata/other/output/formats/audit_results.json +++ b/tests/testdata/other/output/formats/audit_results.json @@ -1,6 +1,7 @@ { "xray_version": "3.98.2", "jas_entitled": true, + "multi_scan_id": "7d5e4733-3f93-11ef-8147-e610d09d7daa", "targets": [ { "target": "/Users/user/ejs-frog-demo", diff --git a/tests/testdata/other/output/formats/audit_simple_json.json b/tests/testdata/other/output/formats/audit_simple_json.json index 962e80a7..a017dae7 100644 --- a/tests/testdata/other/output/formats/audit_simple_json.json +++ b/tests/testdata/other/output/formats/audit_simple_json.json @@ -1,883 +1,917 @@ { - "vulnerabilities": [ - { - "severity": "Critical", - "impactedPackageName": "ejs", - "impactedPackageVersion": "3.1.6", - "impactedPackageType": "npm", - "components": [ - { - "name": "ejs", - "version": "3.1.6" + "vulnerabilities": [ + { + "severity": "Critical", + "impactedPackageName": "ejs", + "impactedPackageVersion": "3.1.6", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6", + "location": { + "file": "/Users/user/ejs-frog-demo" } - ], - "summary": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", - "applicable": "Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2023-29827", - "cvssV2": "", - "cvssV3": "9.8", - "applicability": { - "status": "Applicable", - "scannerDescription": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`", - "evidence": [ - { - "file": "server.js", - "startLine": 15, - "endLine": 15, - "endColumn": 29, - "snippet": "app.set('view engine', 'ejs')", - "reason": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" - } - ] - } + } + ], + "summary": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", + "applicable": "Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2023-29827", + "cvssV2": "", + "cvssV3": "9.8", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`", + "evidence": [ + { + "file": "server.js", + "startLine": 15, + "endLine": 15, + "endColumn": 29, + "snippet": "app.set('view engine', 'ejs')", + "reason": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" + } + ] } - ], - "issueId": "XRAY-520200", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "ejs", - "version": "3.1.6" - } - ] - ], - "jfrogResearchInformation": { - "severity": "Low", - "summary": "Insufficient input validation can lead to template injection in ejs when attackers can control both the rendered template and rendering options.", - "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to bypass ejs' template injection restrictions, by abusing the `closeDelimiter` rendering option, in the case when -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\n\nThe vulnerability was **rightfully disputed** due to the fact that a vulnerable configuration is extremely unlikely to exist in any real-world setup. As such, the maintainers will not provide a fix for this (non-)issue.\n\nExample of a vulnerable application -\n```js\nconst express = require('express')\nconst app = express()\nconst port = 3000\n\napp.set('view engine', 'ejs');\n\napp.get('/page', (req,res) =\u003e {\n res.render('page', req.query); // OPTS (2nd parameter) IS ATTACKER-CONTROLLED\n})\n\napp.listen(port, () =\u003e {\n console.log(\"Example app listening on port ${port}\")\n})\n```\n\nContents of `page.ejs` (very unlikely to be attacker controlled) -\n```js\n%%1\");process.mainModule.require('child_process').execSync('calc');//\n```\n\nIn this case, sending `closeDelimiter` with the same malicious code that already exists at `page.ejs` will trigger the injection -\n`http://127.0.0.1:3000/page?settings[view%20options][closeDelimiter]=1\")%3bprocess.mainModule.require('child_process').execSync('calc')%3b//`", - "severityReasons": [ - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS does not take into account the rarity of a vulnerable configuration to exist", - "isPositive": true - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "The vulnerability can be exploited only under the following conditions -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\nThis vulnerable configuration is extremely unlikely to exist in any real-world setup.", - "isPositive": true - }, - { - "name": "The issue has been disputed by the vendor", - "isPositive": true - }, - { - "name": "The issue has an exploit published", - "description": "Published exploit demonstrates template injection" - } - ] } - }, - { - "severity": "Medium", - "impactedPackageName": "express", - "impactedPackageVersion": "4.18.2", - "impactedPackageType": "npm", - "components": [ + ], + "issueId": "XRAY-520200", + "references": null, + "impactPaths": [ + [ { - "name": "express", - "version": "4.18.2" + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "ejs", + "version": "3.1.6" } - ], - "summary": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", - "applicable": "Not Covered", - "fixedVersions": [ - "[4.19.2]", - "[5.0.0-beta.3]" - ], - "cves": [ + ] + ], + "jfrogResearchInformation": { + "severity": "Low", + "summary": "Insufficient input validation can lead to template injection in ejs when attackers can control both the rendered template and rendering options.", + "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to bypass ejs' template injection restrictions, by abusing the `closeDelimiter` rendering option, in the case when -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\n\nThe vulnerability was **rightfully disputed** due to the fact that a vulnerable configuration is extremely unlikely to exist in any real-world setup. As such, the maintainers will not provide a fix for this (non-)issue.\n\nExample of a vulnerable application -\n```js\nconst express = require('express')\nconst app = express()\nconst port = 3000\n\napp.set('view engine', 'ejs');\n\napp.get('/page', (req,res) =\u003e {\n res.render('page', req.query); // OPTS (2nd parameter) IS ATTACKER-CONTROLLED\n})\n\napp.listen(port, () =\u003e {\n console.log(\"Example app listening on port ${port}\")\n})\n```\n\nContents of `page.ejs` (very unlikely to be attacker controlled) -\n```js\n%%1\");process.mainModule.require('child_process').execSync('calc');//\n```\n\nIn this case, sending `closeDelimiter` with the same malicious code that already exists at `page.ejs` will trigger the injection -\n`http://127.0.0.1:3000/page?settings[view%20options][closeDelimiter]=1\")%3bprocess.mainModule.require('child_process').execSync('calc')%3b//`", + "severityReasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS does not take into account the rarity of a vulnerable configuration to exist", + "isPositive": true + }, { - "id": "CVE-2024-29041", - "cvssV2": "", - "cvssV3": "6.1", - "applicability": { - "status": "Not Covered" - } + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The vulnerability can be exploited only under the following conditions -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\nThis vulnerable configuration is extremely unlikely to exist in any real-world setup.", + "isPositive": true + }, + { + "name": "The issue has been disputed by the vendor", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "Published exploit demonstrates template injection" + } + ] + } + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo" } - ], - "issueId": "XRAY-594935", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "express", - "version": "4.18.2" - } - ] - ], - "jfrogResearchInformation": { - "severity": "" } - }, - { - "severity": "Medium", - "impactedPackageName": "lodash", - "impactedPackageVersion": "4.17.0", - "impactedPackageType": "npm", - "components": [ + ], + "summary": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", + "applicable": "Not Covered", + "fixedVersions": [ + "[4.17.11]" + ], + "cves": [ + { + "id": "CVE-2019-1010266", + "cvssV2": "4.0", + "cvssV3": "6.5", + "applicability": { + "status": "Not Covered" + } + } + ], + "issueId": "XRAY-85049", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, { "name": "lodash", "version": "4.17.0" } - ], - "summary": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", - "applicable": "Not Covered", - "fixedVersions": [ - "[4.17.5]" - ], - "cves": [ - { - "id": "CVE-2018-3721", - "cvssV2": "4.0", - "cvssV3": "6.5", - "applicability": { - "status": "Not Covered" - } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo" } - ], - "issueId": "XRAY-72918", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "lodash", - "version": "4.17.0" - } - ] - ], - "jfrogResearchInformation": { - "severity": "" } - }, - { - "severity": "Medium", - "impactedPackageName": "lodash", - "impactedPackageVersion": "4.17.0", - "impactedPackageType": "npm", - "components": [ + ], + "summary": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", + "applicable": "Not Covered", + "fixedVersions": [ + "[4.17.5]" + ], + "cves": [ + { + "id": "CVE-2018-3721", + "cvssV2": "4.0", + "cvssV3": "6.5", + "applicability": { + "status": "Not Covered" + } + } + ], + "issueId": "XRAY-72918", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, { "name": "lodash", "version": "4.17.0" } - ], - "summary": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", - "applicable": "Not Covered", - "fixedVersions": [ - "[4.17.11]" - ], - "cves": [ + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Medium", + "impactedPackageName": "express", + "impactedPackageVersion": "4.18.2", + "impactedPackageType": "npm", + "components": [ + { + "name": "express", + "version": "4.18.2", + "location": { + "file": "/Users/user/ejs-frog-demo" + } + } + ], + "summary": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", + "applicable": "Not Covered", + "fixedVersions": [ + "[4.19.2]", + "[5.0.0-beta.3]" + ], + "cves": [ + { + "id": "CVE-2024-29041", + "cvssV2": "", + "cvssV3": "6.1", + "applicability": { + "status": "Not Covered" + } + } + ], + "issueId": "XRAY-594935", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, { - "id": "CVE-2019-1010266", - "cvssV2": "4.0", - "cvssV3": "6.5", - "applicability": { - "status": "Not Covered" - } + "name": "express", + "version": "4.18.2" + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Unknown", + "impactedPackageName": "async", + "impactedPackageVersion": "3.2.4", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6", + "location": { + "file": "/Users/user/ejs-frog-demo" + } + } + ], + "summary": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", + "applicable": "Not Covered", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-39249", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Not Covered", + "scannerDescription": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." } - ], - "issueId": "XRAY-85049", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "lodash", - "version": "4.17.0" - } - ] - ], - "jfrogResearchInformation": { - "severity": "" } - }, - { - "severity": "Unknown", - "impactedPackageName": "async", - "impactedPackageVersion": "3.2.4", - "impactedPackageType": "npm", - "components": [ + ], + "issueId": "XRAY-609848", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, { "name": "ejs", "version": "3.1.6" + }, + { + "name": "jake", + "version": "10.8.7" + }, + { + "name": "async", + "version": "3.2.4" } - ], - "summary": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", - "applicable": "Not Covered", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2024-39249", - "cvssV2": "", - "cvssV3": "", - "applicability": { - "status": "Not Covered", - "scannerDescription": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." - } + ] + ], + "jfrogResearchInformation": { + "severity": "Low", + "summary": "ReDoS in Async may lead to denial of service while parsing malformed source code.", + "severityReasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The reported CVSS does not reflect the severity of the vulnerability.", + "isPositive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "To exploit this issue an attacker must change the source code of the application. In cases where an attacker can already modify (or fully control) the source code, the attacker can immediately achieve arbitrary code execution - thus this issue has almost no security impact.", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "A proof-of-concept has been published in the advisory." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The issue requires the use of the `async.autoInject` function to be vulnerable.", + "isPositive": true + } + ] + } + }, + { + "severity": "Critical", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo" + } + } + ], + "summary": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.12]" + ], + "cves": [ + { + "id": "CVE-2019-10744", + "cvssV2": "6.4", + "cvssV3": "9.1", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present.", + "evidence": [ + { + "file": "server.js", + "startLine": 1, + "endLine": 1, + "endColumn": 31, + "snippet": "Object.freeze(Object.prototype)", + "reason": "Prototype pollution `Object.freeze` remediation was detected" + } + ] + } + } + ], + "issueId": "XRAY-85679", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "High", + "summary": "Insufficient input validation in lodash defaultsDeep() leads to prototype pollution.", + "details": "[lodash](https://www.npmjs.com/package/lodash) is a modern JavaScript utility library delivering modularity, performance, \u0026 extras.\n\nThe function `defaultsDeep` was found to be vulnerable to prototype pollution, when accepting arbitrary source objects from untrusted input\n\nExample of code vulnerable to this issue - \n```js\nconst lodash = require('lodash'); \nconst evilsrc = {constructor: {prototype: {evilkey: \"evilvalue\"}}};\nlodash.defaultsDeep({}, evilsrc)\n```", + "severityReasons": [ + { + "name": "The issue has an exploit published", + "description": "A public PoC demonstrates exploitation of this issue" + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", + "isPositive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find remote input that propagates into the `defaultsDeep` method (2nd arg)", + "isPositive": true } ], - "issueId": "XRAY-609848", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "ejs", - "version": "3.1.6" - }, - { - "name": "jake", - "version": "10.8.7" - }, - { - "name": "async", - "version": "3.2.4" - } - ] - ], - "jfrogResearchInformation": { - "severity": "Low", - "summary": "ReDoS in Async may lead to denial of service while parsing malformed source code.", - "severityReasons": [ - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The reported CVSS does not reflect the severity of the vulnerability.", - "isPositive": true - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "To exploit this issue an attacker must change the source code of the application. In cases where an attacker can already modify (or fully control) the source code, the attacker can immediately achieve arbitrary code execution - thus this issue has almost no security impact.", - "isPositive": true - }, - { - "name": "The issue has an exploit published", - "description": "A proof-of-concept has been published in the advisory." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The issue requires the use of the `async.autoInject` function to be vulnerable.", - "isPositive": true - } - ] + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." + } + }, + { + "severity": "Critical", + "impactedPackageName": "ejs", + "impactedPackageVersion": "3.1.6", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6", + "location": { + "file": "/Users/user/ejs-frog-demo" + } } - }, - { - "severity": "Critical", - "impactedPackageName": "ejs", - "impactedPackageVersion": "3.1.6", - "impactedPackageType": "npm", - "components": [ + ], + "summary": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", + "applicable": "Not Applicable", + "fixedVersions": [ + "[3.1.7]" + ], + "cves": [ + { + "id": "CVE-2022-29078", + "cvssV2": "7.5", + "cvssV3": "9.8", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "evidence": [ + { + "file": "server.js", + "startLine": 1, + "endLine": 1, + "endColumn": 31, + "snippet": "Object.freeze(Object.prototype)", + "reason": "Prototype pollution `Object.freeze` remediation was detected" + } + ] + } + } + ], + "issueId": "XRAY-209002", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, { "name": "ejs", "version": "3.1.6" } - ], - "summary": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", - "applicable": "Not Applicable", - "fixedVersions": [ - "[3.1.7]" - ], - "cves": [ - { - "id": "CVE-2022-29078", - "cvssV2": "7.5", - "cvssV3": "9.8", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", - "evidence": [ - { - "file": "server.js", - "startLine": 1, - "endLine": 1, - "endColumn": 31, - "snippet": "Object.freeze(Object.prototype)", - "reason": "Prototype pollution `Object.freeze` remediation was detected" - } - ] - } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Insufficient input validation in EJS enables attackers to perform template injection when attacker can control the rendering options.", + "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to perform template injection on the `opts.outputFunctionName` variable, since the variable is injected into the template body without any escaping. Although it is unlikely that the attacker can directly control the `outputFunctionName` property, it is possible that it can be influenced in conjunction with a prototype pollution vulnerability.\n\nOnce template injection is achieved, the attacker can immediately perform remote code execution since the template engine (EJS) allows executing arbitrary JavaScript code.\n\nExample of a vulnerable Node.js application -\n```js\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst lodash = require('lodash');\nconst ejs = require('ejs');\n\nconst app = express();\n\napp\n .use(bodyParser.urlencoded({extended: true}))\n .use(bodyParser.json());\n\napp.set('views', './');\napp.set('view engine', 'ejs');\n\napp.get(\"/\", (req, res) =\u003e {\n res.render('index');\n});\n\napp.post(\"/\", (req, res) =\u003e {\n let data = {};\n let input = JSON.parse(req.body.content);\n lodash.defaultsDeep(data, input);\n res.json({message: \"OK\"});\n});\n\nlet server = app.listen(8086, '0.0.0.0', function() {\n console.log('Listening on port %d', server.address().port);\n});\n```\n\nExploiting the above example for RCE -\n`curl 127.0.0.1:8086 -v --data 'content={\"constructor\": {\"prototype\": {\"outputFunctionName\": \"a; return global.process.mainModule.constructor._load(\\\"child_process\\\").execSync(\\\"whoami\\\"); //\"}}}'\n`\n\nDue to the prototype pollution in the `lodash.defaultsDeep` call, an attacker can inject the `outputFunctionName` property with an arbitrary value. The chosen value executes an arbitrary process via the `child_process` module.", + "severityReasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker has to find a way to get their malicious input to `opts.outputFunctionName`, which will usually require exploitation of a prototype pollution vulnerability somewhere else in the code. However, there could be cases where the attacker can pass malicious data to the render function directly because of design problems in other code using EJS.", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "There are multiple examples of exploits for this vulnerability online." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Successful exploitation of this vulnerability leads to remote code execution." } ], - "issueId": "XRAY-209002", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "ejs", - "version": "3.1.6" - } - ] - ], - "jfrogResearchInformation": { - "severity": "Medium", - "summary": "Insufficient input validation in EJS enables attackers to perform template injection when attacker can control the rendering options.", - "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to perform template injection on the `opts.outputFunctionName` variable, since the variable is injected into the template body without any escaping. Although it is unlikely that the attacker can directly control the `outputFunctionName` property, it is possible that it can be influenced in conjunction with a prototype pollution vulnerability.\n\nOnce template injection is achieved, the attacker can immediately perform remote code execution since the template engine (EJS) allows executing arbitrary JavaScript code.\n\nExample of a vulnerable Node.js application -\n```js\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst lodash = require('lodash');\nconst ejs = require('ejs');\n\nconst app = express();\n\napp\n .use(bodyParser.urlencoded({extended: true}))\n .use(bodyParser.json());\n\napp.set('views', './');\napp.set('view engine', 'ejs');\n\napp.get(\"/\", (req, res) =\u003e {\n res.render('index');\n});\n\napp.post(\"/\", (req, res) =\u003e {\n let data = {};\n let input = JSON.parse(req.body.content);\n lodash.defaultsDeep(data, input);\n res.json({message: \"OK\"});\n});\n\nlet server = app.listen(8086, '0.0.0.0', function() {\n console.log('Listening on port %d', server.address().port);\n});\n```\n\nExploiting the above example for RCE -\n`curl 127.0.0.1:8086 -v --data 'content={\"constructor\": {\"prototype\": {\"outputFunctionName\": \"a; return global.process.mainModule.constructor._load(\\\"child_process\\\").execSync(\\\"whoami\\\"); //\"}}}'\n`\n\nDue to the prototype pollution in the `lodash.defaultsDeep` call, an attacker can inject the `outputFunctionName` property with an arbitrary value. The chosen value executes an arbitrary process via the `child_process` module.", - "severityReasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "The attacker has to find a way to get their malicious input to `opts.outputFunctionName`, which will usually require exploitation of a prototype pollution vulnerability somewhere else in the code. However, there could be cases where the attacker can pass malicious data to the render function directly because of design problems in other code using EJS.", - "isPositive": true - }, - { - "name": "The issue has an exploit published", - "description": "There are multiple examples of exploits for this vulnerability online." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Successful exploitation of this vulnerability leads to remote code execution." - } - ], - "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\nNote that this mitigation is supposed to stop any prototype pollution attacks which can allow an attacker to control the `opts.outputFunctionName` parameter indirectly.\n\nThe mitigation will not stop any (extremely unlikely) scenarios where the JavaScript code allows external input to directly affect `opts.outputFunctionName`." + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\nNote that this mitigation is supposed to stop any prototype pollution attacks which can allow an attacker to control the `opts.outputFunctionName` parameter indirectly.\n\nThe mitigation will not stop any (extremely unlikely) scenarios where the JavaScript code allows external input to directly affect `opts.outputFunctionName`." + } + }, + { + "severity": "High", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo" + } } - }, - { - "severity": "Critical", - "impactedPackageName": "lodash", - "impactedPackageVersion": "4.17.0", - "impactedPackageType": "npm", - "components": [ + ], + "summary": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.21]" + ], + "cves": [ + { + "id": "CVE-2021-23337", + "cvssV2": "6.5", + "cvssV3": "7.2", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." + } + } + ], + "issueId": "XRAY-140575", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, { "name": "lodash", "version": "4.17.0" } - ], - "summary": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", - "applicable": "Not Applicable", - "fixedVersions": [ - "[4.17.12]" - ], - "cves": [ - { - "id": "CVE-2019-10744", - "cvssV2": "6.4", - "cvssV3": "9.1", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present.", - "evidence": [ - { - "file": "server.js", - "startLine": 1, - "endLine": 1, - "endColumn": 31, - "snippet": "Object.freeze(Object.prototype)", - "reason": "Prototype pollution `Object.freeze` remediation was detected" - } - ] - } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Improper sanitization in the lodash template function leads to JavaScript code injection through the options argument.", + "details": "JavaScript-based applications (both frontend and backend) that use the [template function](https://lodash.com/docs/4.17.15#template) -`_.template([string=''], [options={}])` from the [lodash](https://lodash.com/) utility library and provide the `options` argument (specifically the `variable` option) from untrusted user input, are vulnerable to JavaScript code injection. This issue can be easily exploited, and an exploitation example is [publicly available](https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c#diff-a561630bb56b82342bc66697aee2ad96efddcbc9d150665abd6fb7ecb7c0ab2fR22303) in the fix tests that was introduced in version 4.17.21 - \n```js\nlodash.template('', { variable: '){console.log(process.env)}; with(obj' })()\n```", + "severityReasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "It is highly unlikely that a JS program will accept arbitrary remote input into the template's `options` argument", + "isPositive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must find remote input that propagates into the `options` argument of a `template` call", + "isPositive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Leads to remote code execution through JS code injection" + }, + { + "name": "The issue has an exploit published", + "description": "Published exploit demonstrates arbitrary JS code execution" + } + ] + } + }, + { + "severity": "High", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo" } - ], - "issueId": "XRAY-85679", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "lodash", - "version": "4.17.0" - } - ] - ], - "jfrogResearchInformation": { - "severity": "High", - "summary": "Insufficient input validation in lodash defaultsDeep() leads to prototype pollution.", - "details": "[lodash](https://www.npmjs.com/package/lodash) is a modern JavaScript utility library delivering modularity, performance, \u0026 extras.\n\nThe function `defaultsDeep` was found to be vulnerable to prototype pollution, when accepting arbitrary source objects from untrusted input\n\nExample of code vulnerable to this issue - \n```js\nconst lodash = require('lodash'); \nconst evilsrc = {constructor: {prototype: {evilkey: \"evilvalue\"}}};\nlodash.defaultsDeep({}, evilsrc)\n```", - "severityReasons": [ - { - "name": "The issue has an exploit published", - "description": "A public PoC demonstrates exploitation of this issue" - }, - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", - "isPositive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "An attacker must find remote input that propagates into the `defaultsDeep` method (2nd arg)", - "isPositive": true - } - ], - "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." } - }, - { - "severity": "High", - "impactedPackageName": "lodash", - "impactedPackageVersion": "4.17.0", - "impactedPackageType": "npm", - "components": [ + ], + "summary": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.19]" + ], + "cves": [ + { + "id": "CVE-2020-8203", + "cvssV2": "5.8", + "cvssV3": "7.4", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." + } + } + ], + "issueId": "XRAY-114089", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, { "name": "lodash", "version": "4.17.0" } - ], - "summary": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", - "applicable": "Not Applicable", - "fixedVersions": [ - "[4.17.21]" - ], - "cves": [ + ] + ], + "jfrogResearchInformation": { + "severity": "Critical", + "summary": "Prototype pollution in lodash object merging and zipping functions leads to code injection.", + "details": "[lodash](https://lodash.com/) is a JavaScript library which provides utility functions for common programming tasks.\n\nJavaScript frontend and Node.js-based backend applications that merge or zip objects using the lodash functions `mergeWith`, `merge` and `zipObjectDeep` are vulnerable to [prototype pollution](https://medium.com/node-modules/what-is-prototype-pollution-and-why-is-it-such-a-big-deal-2dd8d89a93c) if one or more of the objects it receives as arguments are obtained from user input. \nAn attacker controlling this input given to the vulnerable functions can inject properties to JavaScript special objects such as [Object.prototype](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes) from which all JavaScript objects inherit properties and methods. Any change on `Object.prototype` properties will then propagate through the prototype chain inheritance to all of the objects in a JavaScript application. This in turn would allow an attacker to add new properties or modify existing properties which will have application specific implications that could lead to DoS (denial of service), authentication bypass, privilege escalation and even RCE (remote code execution) in [some cases](https://youtu.be/LUsiFV3dsK8?t=1152). \nAs an example for privilege escalation, consider a JavaScript application that has a `user` object which has a Boolean property of `user.isAdmin` which is used to decide which actions the user may take. If an attacker can modify or add the `isAdmin` property through prototype pollution, it can escalate the privileges of its own user to those of an admin. \nAs exploitation is usually application specific, successful exploitation is much more likely if an attacker have access to the JavaScript application code. As such, frontend applications are more vulnerable to this vulnerability than Node.js backend applications.", + "severityReasons": [ + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "isPositive": true + }, + { + "name": "The issue can be exploited by attackers over the network" + }, { - "id": "CVE-2021-23337", - "cvssV2": "6.5", - "cvssV3": "7.2", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." - } + "name": "The issue is trivial to exploit and does not require a published writeup or PoC" } ], - "issueId": "XRAY-140575", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "lodash", - "version": "4.17.0" - } - ] - ], - "jfrogResearchInformation": { - "severity": "Medium", - "summary": "Improper sanitization in the lodash template function leads to JavaScript code injection through the options argument.", - "details": "JavaScript-based applications (both frontend and backend) that use the [template function](https://lodash.com/docs/4.17.15#template) -`_.template([string=''], [options={}])` from the [lodash](https://lodash.com/) utility library and provide the `options` argument (specifically the `variable` option) from untrusted user input, are vulnerable to JavaScript code injection. This issue can be easily exploited, and an exploitation example is [publicly available](https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c#diff-a561630bb56b82342bc66697aee2ad96efddcbc9d150665abd6fb7ecb7c0ab2fR22303) in the fix tests that was introduced in version 4.17.21 - \n```js\nlodash.template('', { variable: '){console.log(process.env)}; with(obj' })()\n```", - "severityReasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "It is highly unlikely that a JS program will accept arbitrary remote input into the template's `options` argument", - "isPositive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker must find remote input that propagates into the `options` argument of a `template` call", - "isPositive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Leads to remote code execution through JS code injection" - }, - { - "name": "The issue has an exploit published", - "description": "Published exploit demonstrates arbitrary JS code execution" - } - ] + "remediation": "##### Deployment mitigations\n\nAs general guidelines against prototype pollution, first consider not merging objects originating from user input or using a Map structure instead of an object. If merging objects is needed, look into creating objects without a prototype with `Object.create(null)` or into freezing `Object.prototype` with `Object.freeze()`. Finally, it is always best to perform input validation with a a [JSON schema validator](https://github.com/ajv-validator/ajv), which could mitigate this issue entirely in many cases." + } + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo" + } } - }, - { - "severity": "High", - "impactedPackageName": "lodash", - "impactedPackageVersion": "4.17.0", - "impactedPackageType": "npm", - "components": [ + ], + "summary": "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.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.11]" + ], + "cves": [ + { + "id": "CVE-2018-16487", + "cvssV2": "6.8", + "cvssV3": "5.6", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "evidence": [ + { + "file": "server.js", + "startLine": 1, + "endLine": 1, + "endColumn": 31, + "snippet": "Object.freeze(Object.prototype)", + "reason": "Prototype pollution `Object.freeze` remediation was detected" + } + ] + } + } + ], + "issueId": "XRAY-75300", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, { "name": "lodash", "version": "4.17.0" } - ], - "summary": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", - "applicable": "Not Applicable", - "fixedVersions": [ - "[4.17.19]" - ], - "cves": [ + ] + ], + "jfrogResearchInformation": { + "severity": "High", + "summary": "Insufficient input validation in the Lodash library leads to prototype pollution.", + "details": "The [Lodash](https://lodash.com/) library is an open-source JavaScript project that simplifies operations on string, arrays, numbers, and other objects. It is widely used in connected devices. \n\nThe `merge`, `mergeWith`, and `defaultsDeep` methods in Lodash are vulnerable to [prototype pollution](https://shieldfy.io/security-wiki/prototype-pollution/introduction-to-prototype-pollution/). Attackers can exploit this vulnerability by specifying a crafted `sources` parameter to any of these methods, which can modify the prototype properties of the `Object`, `Function`, `Array`, `String`, `Number`, and `Boolean` objects. A public [exploit](https://hackerone.com/reports/380873) exists which performs the prototype pollution with an arbitrary key and value.\n\nThe library implementation has a bug in the `safeGet()` function in the `lodash.js` module that allows for adding or modifying `prototype` properties of various objects. The official [solution](https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad) fixes the bug by explicitly forbidding the addition or modification of `prototype` properties.\n\nA related CVE (CVE-2018-3721) covers the same issue prior to Lodash version 4.17.5, but the fix for that was incomplete.", + "severityReasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find remote input that propagates into one of the following methods - \n* `merge` - 2nd argument\n* `mergeWith` - 2nd argument\n* `defaultsDeep` - 2nd argument", + "isPositive": true + }, { - "id": "CVE-2020-8203", - "cvssV2": "5.8", - "cvssV3": "7.4", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." - } + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "A public PoC demonstrated exploitation by injecting an attacker controlled key and value into the prototype" } ], - "issueId": "XRAY-114089", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "lodash", - "version": "4.17.0" - } - ] - ], - "jfrogResearchInformation": { - "severity": "Critical", - "summary": "Prototype pollution in lodash object merging and zipping functions leads to code injection.", - "details": "[lodash](https://lodash.com/) is a JavaScript library which provides utility functions for common programming tasks.\n\nJavaScript frontend and Node.js-based backend applications that merge or zip objects using the lodash functions `mergeWith`, `merge` and `zipObjectDeep` are vulnerable to [prototype pollution](https://medium.com/node-modules/what-is-prototype-pollution-and-why-is-it-such-a-big-deal-2dd8d89a93c) if one or more of the objects it receives as arguments are obtained from user input. \nAn attacker controlling this input given to the vulnerable functions can inject properties to JavaScript special objects such as [Object.prototype](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes) from which all JavaScript objects inherit properties and methods. Any change on `Object.prototype` properties will then propagate through the prototype chain inheritance to all of the objects in a JavaScript application. This in turn would allow an attacker to add new properties or modify existing properties which will have application specific implications that could lead to DoS (denial of service), authentication bypass, privilege escalation and even RCE (remote code execution) in [some cases](https://youtu.be/LUsiFV3dsK8?t=1152). \nAs an example for privilege escalation, consider a JavaScript application that has a `user` object which has a Boolean property of `user.isAdmin` which is used to decide which actions the user may take. If an attacker can modify or add the `isAdmin` property through prototype pollution, it can escalate the privileges of its own user to those of an admin. \nAs exploitation is usually application specific, successful exploitation is much more likely if an attacker have access to the JavaScript application code. As such, frontend applications are more vulnerable to this vulnerability than Node.js backend applications.", - "severityReasons": [ - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "isPositive": true - }, - { - "name": "The issue can be exploited by attackers over the network" - }, - { - "name": "The issue is trivial to exploit and does not require a published writeup or PoC" - } - ], - "remediation": "##### Deployment mitigations\n\nAs general guidelines against prototype pollution, first consider not merging objects originating from user input or using a Map structure instead of an object. If merging objects is needed, look into creating objects without a prototype with `Object.create(null)` or into freezing `Object.prototype` with `Object.freeze()`. Finally, it is always best to perform input validation with a a [JSON schema validator](https://github.com/ajv-validator/ajv), which could mitigate this issue entirely in many cases." + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." + } + }, + { + "severity": "Medium", + "impactedPackageName": "ejs", + "impactedPackageVersion": "3.1.6", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6", + "location": { + "file": "/Users/user/ejs-frog-demo" + } } - }, - { - "severity": "Medium", - "impactedPackageName": "ejs", - "impactedPackageVersion": "3.1.6", - "impactedPackageType": "npm", - "components": [ + ], + "summary": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[3.1.10]" + ], + "cves": [ + { + "id": "CVE-2024-33883", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `ejs.compile()` is called." + } + } + ], + "issueId": "XRAY-599735", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, { "name": "ejs", "version": "3.1.6" } - ], - "summary": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", - "applicable": "Not Applicable", - "fixedVersions": [ - "[3.1.10]" - ], - "cves": [ - { - "id": "CVE-2024-33883", - "cvssV2": "", - "cvssV3": "", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether the vulnerable function `ejs.compile()` is called." - } - } - ], - "issueId": "XRAY-599735", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "ejs", - "version": "3.1.6" - } - ] - ], - "jfrogResearchInformation": { - "severity": "Medium", - "summary": "Insufficient input validation in EJS may lead to prototype pollution.", - "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as `EJS`, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nA prototype pollution gadget within the EJS template engine could potentially be leveraged by attackers to achieve remote code execution or DoS via prototype pollution.\n\n```\nfunction Template(text, opts) {\n opts = opts || utils.createNullProtoObjWherePossible();\n```\n\nWhen checking for the presence of a property within an object variable, the lookup scope isn't explicitly defined. In JavaScript, the absence of a defined lookup scope prompts a search up to the root prototype (`Object.prototype`). This could potentially be under the control of an attacker if another prototype pollution vulnerability is present within the application.\n\nIf the application server is using the EJS as the backend template engine, and there is another prototype pollution vulnerability in the application, then the attacker could leverage the found gadgets in the EJS template engine to escalate the prototype pollution to remote code execution or DoS.\n\nThe following code will execute a command on the server by polluting `opts.escapeFunction`:\n \n```\nconst express = require('express');\nconst app = express();\nconst port = 8008;\nconst ejs = require('ejs');\n\n// Set EJS as the view engine\napp.set('view engine', 'ejs');\n\napp.get('/', (req, res) =\u003e {\n \n const data = {title: 'Welcome', message: 'Hello'};\n\n // Sample EJS template string\n const templateString = `\u003chtml\u003e\u003chead\u003e\u003ctitle\u003e\u003c%= title %\u003e\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003ch1\u003e\u003c%= message %\u003e\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e`;\n\n const { exec } = require('child_process');\n\n function myFunc() {\n exec('bash -c \"echo 123\"', (error, stdout, stderr) =\u003e {\n if (error) {\n console.error(`exec error: ${error}`);\n return;\n }\n if (stderr){\n console.log(`stderr : ${stderr}`);\n return;\n }\n // Handle success\n console.log(`Command executed successfully. Output: ${stdout}`);\n });\n }\n\n const options = {client:false};\n\n Object.prototype.escapeFunction = myFunc;\n \n const compiledTemplate = ejs.compile(templateString, options);\n const renderedHtml = compiledTemplate(data);\n res.send(renderedHtml);\n});\n\n// Start the server\napp.listen(port, () =\u003e {\n console.log(`Server is running on http://localhost:${port}`);\n});\n```", - "severityReasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "Attackers can only leverage this vulnerability when the application server is using the EJS as the backend template engine. Moreover, there must be a second prototype pollution vulnerability in the application.", - "isPositive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "CVSS does not take into account the unlikely prerequisites necessary for exploitation.", - "isPositive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "A prototype pollution attack allows the attacker to inject new properties into all JavaScript objects.\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable." - } - ] - } - }, - { + ] + ], + "jfrogResearchInformation": { "severity": "Medium", - "impactedPackageName": "lodash", - "impactedPackageVersion": "4.17.0", - "impactedPackageType": "npm", - "components": [ + "summary": "Insufficient input validation in EJS may lead to prototype pollution.", + "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as `EJS`, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nA prototype pollution gadget within the EJS template engine could potentially be leveraged by attackers to achieve remote code execution or DoS via prototype pollution.\n\n```\nfunction Template(text, opts) {\n opts = opts || utils.createNullProtoObjWherePossible();\n```\n\nWhen checking for the presence of a property within an object variable, the lookup scope isn't explicitly defined. In JavaScript, the absence of a defined lookup scope prompts a search up to the root prototype (`Object.prototype`). This could potentially be under the control of an attacker if another prototype pollution vulnerability is present within the application.\n\nIf the application server is using the EJS as the backend template engine, and there is another prototype pollution vulnerability in the application, then the attacker could leverage the found gadgets in the EJS template engine to escalate the prototype pollution to remote code execution or DoS.\n\nThe following code will execute a command on the server by polluting `opts.escapeFunction`:\n \n```\nconst express = require('express');\nconst app = express();\nconst port = 8008;\nconst ejs = require('ejs');\n\n// Set EJS as the view engine\napp.set('view engine', 'ejs');\n\napp.get('/', (req, res) =\u003e {\n \n const data = {title: 'Welcome', message: 'Hello'};\n\n // Sample EJS template string\n const templateString = `\u003chtml\u003e\u003chead\u003e\u003ctitle\u003e\u003c%= title %\u003e\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003ch1\u003e\u003c%= message %\u003e\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e`;\n\n const { exec } = require('child_process');\n\n function myFunc() {\n exec('bash -c \"echo 123\"', (error, stdout, stderr) =\u003e {\n if (error) {\n console.error(`exec error: ${error}`);\n return;\n }\n if (stderr){\n console.log(`stderr : ${stderr}`);\n return;\n }\n // Handle success\n console.log(`Command executed successfully. Output: ${stdout}`);\n });\n }\n\n const options = {client:false};\n\n Object.prototype.escapeFunction = myFunc;\n \n const compiledTemplate = ejs.compile(templateString, options);\n const renderedHtml = compiledTemplate(data);\n res.send(renderedHtml);\n});\n\n// Start the server\napp.listen(port, () =\u003e {\n console.log(`Server is running on http://localhost:${port}`);\n});\n```", + "severityReasons": [ { - "name": "lodash", - "version": "4.17.0" - } - ], - "summary": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", - "applicable": "Not Applicable", - "fixedVersions": [ - "[4.17.21]" - ], - "cves": [ + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "Attackers can only leverage this vulnerability when the application server is using the EJS as the backend template engine. Moreover, there must be a second prototype pollution vulnerability in the application.", + "isPositive": true + }, { - "id": "CVE-2020-28500", - "cvssV2": "5.0", - "cvssV3": "5.3", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." - } + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "CVSS does not take into account the unlikely prerequisites necessary for exploitation.", + "isPositive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "A prototype pollution attack allows the attacker to inject new properties into all JavaScript objects.\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable." + } + ] + } + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo" } - ], - "issueId": "XRAY-140562", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "lodash", - "version": "4.17.0" - } - ] - ], - "jfrogResearchInformation": { - "severity": "Medium", - "summary": "ReDoS in lodash could lead to a denial of service when handling untrusted strings.", - "details": "JavaScript-based applications that use [lodash](https://github.com/lodash/lodash) and specifically the [_.toNumber](https://lodash.com/docs/4.17.15#toNumber), [_.trim](https://lodash.com/docs/4.17.15#trim) and [_.trimEnd](https://lodash.com/docs/4.17.15#trimEnd) functions, could be vulnerable to DoS (Denial of Service) through a faulty regular expression that introduces a ReDoS (Regular Expression DoS) vulnerability. This vulnerability is only triggered if untrusted user input flows into these vulnerable functions and the attacker can supply arbitrary long strings (over 50kB) that contain whitespaces. \n\nOn a modern Core i7-based system, calling the vulnerable functions with a 50kB string could take between 2 to 3 seconds to execute and 4.5 minutes for a longer 500kB string. The fix improved the regular expression performance so it took only a few milliseconds on the same Core i7-based system. This vulnerability is easily exploitable as all is required is to build a string that triggers it as can be seen in this PoC reproducing code - \n\n```js\nvar untrusted_user_input_50k = \"a\" + ' '.repeat(50000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_50k); // should take a few seconds to run\nvar untrusted_user_input_500k = \"a\" + ' '.repeat(500000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_500k); // should take a few minutes to run\n```", - "severityReasons": [ - { - "name": "The issue has an exploit published", - "description": "Public exploit demonstrated ReDoS" - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "Exploitation depends on parsing user input by the `.toNumber`, `.trim` or `.trimEnd` `lodash` functions, and requires the input to contain whitespaces and be very long (over 50KB)", - "isPositive": true - } - ], - "remediation": "##### Deployment mitigations\n\nTrim untrusted strings based on size before providing it to the vulnerable functions by using the `substring` function to with a fixed maximum size like so - ```js untrusted_user_input.substring(0, max_string_size_less_than_50kB); ```" } - }, - { - "severity": "Medium", - "impactedPackageName": "lodash", - "impactedPackageVersion": "4.17.0", - "impactedPackageType": "npm", - "components": [ + ], + "summary": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.21]" + ], + "cves": [ + { + "id": "CVE-2020-28500", + "cvssV2": "5.0", + "cvssV3": "5.3", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." + } + } + ], + "issueId": "XRAY-140562", + "references": null, + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, { "name": "lodash", "version": "4.17.0" } - ], - "summary": "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.", - "applicable": "Not Applicable", - "fixedVersions": [ - "[4.17.11]" - ], - "cves": [ - { - "id": "CVE-2018-16487", - "cvssV2": "6.8", - "cvssV3": "5.6", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", - "evidence": [ - { - "file": "server.js", - "startLine": 1, - "endLine": 1, - "endColumn": 31, - "snippet": "Object.freeze(Object.prototype)", - "reason": "Prototype pollution `Object.freeze` remediation was detected" - } - ] - } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "ReDoS in lodash could lead to a denial of service when handling untrusted strings.", + "details": "JavaScript-based applications that use [lodash](https://github.com/lodash/lodash) and specifically the [_.toNumber](https://lodash.com/docs/4.17.15#toNumber), [_.trim](https://lodash.com/docs/4.17.15#trim) and [_.trimEnd](https://lodash.com/docs/4.17.15#trimEnd) functions, could be vulnerable to DoS (Denial of Service) through a faulty regular expression that introduces a ReDoS (Regular Expression DoS) vulnerability. This vulnerability is only triggered if untrusted user input flows into these vulnerable functions and the attacker can supply arbitrary long strings (over 50kB) that contain whitespaces. \n\nOn a modern Core i7-based system, calling the vulnerable functions with a 50kB string could take between 2 to 3 seconds to execute and 4.5 minutes for a longer 500kB string. The fix improved the regular expression performance so it took only a few milliseconds on the same Core i7-based system. This vulnerability is easily exploitable as all is required is to build a string that triggers it as can be seen in this PoC reproducing code - \n\n```js\nvar untrusted_user_input_50k = \"a\" + ' '.repeat(50000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_50k); // should take a few seconds to run\nvar untrusted_user_input_500k = \"a\" + ' '.repeat(500000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_500k); // should take a few minutes to run\n```", + "severityReasons": [ + { + "name": "The issue has an exploit published", + "description": "Public exploit demonstrated ReDoS" + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "Exploitation depends on parsing user input by the `.toNumber`, `.trim` or `.trimEnd` `lodash` functions, and requires the input to contain whitespaces and be very long (over 50KB)", + "isPositive": true } ], - "issueId": "XRAY-75300", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "lodash", - "version": "4.17.0" - } - ] - ], - "jfrogResearchInformation": { - "severity": "High", - "summary": "Insufficient input validation in the Lodash library leads to prototype pollution.", - "details": "The [Lodash](https://lodash.com/) library is an open-source JavaScript project that simplifies operations on string, arrays, numbers, and other objects. It is widely used in connected devices. \n\nThe `merge`, `mergeWith`, and `defaultsDeep` methods in Lodash are vulnerable to [prototype pollution](https://shieldfy.io/security-wiki/prototype-pollution/introduction-to-prototype-pollution/). Attackers can exploit this vulnerability by specifying a crafted `sources` parameter to any of these methods, which can modify the prototype properties of the `Object`, `Function`, `Array`, `String`, `Number`, and `Boolean` objects. A public [exploit](https://hackerone.com/reports/380873) exists which performs the prototype pollution with an arbitrary key and value.\n\nThe library implementation has a bug in the `safeGet()` function in the `lodash.js` module that allows for adding or modifying `prototype` properties of various objects. The official [solution](https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad) fixes the bug by explicitly forbidding the addition or modification of `prototype` properties.\n\nA related CVE (CVE-2018-3721) covers the same issue prior to Lodash version 4.17.5, but the fix for that was incomplete.", - "severityReasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "An attacker must find remote input that propagates into one of the following methods - \n* `merge` - 2nd argument\n* `mergeWith` - 2nd argument\n* `defaultsDeep` - 2nd argument", - "isPositive": true - }, - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", - "isPositive": true - }, - { - "name": "The issue has an exploit published", - "description": "A public PoC demonstrated exploitation by injecting an attacker controlled key and value into the prototype" - } - ], - "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." - } - } - ], - "securityViolations": null, - "licensesViolations": null, - "licenses": null, - "operationalRiskViolations": null, - "secrets": [ - { - "severity": "Medium", - "file": "fake-creds.txt", - "startLine": 1, - "endLine": 1, - "snippet": "AKI************", - "finding": "Secret keys were found" - }, - { - "severity": "Medium", - "file": "fake-creds.txt", - "startLine": 2, - "endLine": 2, - "snippet": "Sqc************", - "finding": "Secret keys were found" - }, - { - "severity": "Medium", - "file": "fake-creds.txt", - "startLine": 3, - "endLine": 3, - "snippet": "gho************", - "finding": "Secret keys were found" - }, - { - "severity": "Medium", - "file": "server.js", - "startLine": 11, - "startColumn": 15, - "endLine": 11, - "endColumn": 15, - "snippet": "AKI************", - "finding": "Secret keys were found" - }, - { - "severity": "Medium", - "file": "server.js", - "startLine": 12, - "startColumn": 12, - "endLine": 12, - "endColumn": 12, - "snippet": "\"Sq************", - "finding": "Secret keys were found" + "remediation": "##### Deployment mitigations\n\nTrim untrusted strings based on size before providing it to the vulnerable functions by using the `substring` function to with a fixed maximum size like so - ```js untrusted_user_input.substring(0, max_string_size_less_than_50kB); ```" } - ], - "iacViolations": null, - "sastViolations": [ - { - "severity": "High", - "file": "server.js", - "startLine": 27, - "startColumn": 28, - "endLine": 27, - "endColumn": 37, - "snippet": "req.query", - "finding": "Template Object Injection", - "scannerDescription": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n", - "codeFlow": [ - [ - { - "file": "server.js", - "startLine": 22, - "startColumn": 23, - "endLine": 22, - "endColumn": 26, - "snippet": "req" - }, - { - "file": "server.js", - "startLine": 27, - "startColumn": 28, - "endLine": 27, - "endColumn": 31, - "snippet": "req" - }, - { - "file": "server.js", - "startLine": 27, - "startColumn": 28, - "endLine": 27, - "endColumn": 37, - "snippet": "req.query" - } - ] + } + ], + "securityViolations": null, + "licensesViolations": null, + "licenses": null, + "operationalRiskViolations": null, + "secrets": [ + { + "severity": "Medium", + "file": "server.js", + "startLine": 11, + "startColumn": 15, + "endLine": 11, + "endColumn": 15, + "snippet": "AKI************", + "finding": "Secret keys were found", + "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + { + "severity": "Medium", + "file": "server.js", + "startLine": 12, + "startColumn": 12, + "endLine": 12, + "endColumn": 12, + "snippet": "\"Sq************", + "finding": "Secret keys were found", + "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + { + "severity": "Medium", + "file": "fake-creds.txt", + "startLine": 1, + "endLine": 1, + "snippet": "AKI************", + "finding": "Secret keys were found", + "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + { + "severity": "Medium", + "file": "fake-creds.txt", + "startLine": 2, + "endLine": 2, + "snippet": "Sqc************", + "finding": "Secret keys were found", + "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + { + "severity": "Medium", + "file": "fake-creds.txt", + "startLine": 3, + "endLine": 3, + "snippet": "gho************", + "finding": "Secret keys were found", + "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + } + ], + "iacViolations": null, + "sastViolations": [ + { + "severity": "High", + "file": "server.js", + "startLine": 27, + "startColumn": 28, + "endLine": 27, + "endColumn": 37, + "snippet": "req.query", + "finding": "Template Object Injection", + "scannerDescription": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n", + "codeFlow": [ + [ + { + "file": "server.js", + "startLine": 22, + "startColumn": 23, + "endLine": 22, + "endColumn": 26, + "snippet": "req" + }, + { + "file": "server.js", + "startLine": 27, + "startColumn": 28, + "endLine": 27, + "endColumn": 31, + "snippet": "req" + }, + { + "file": "server.js", + "startLine": 27, + "startColumn": 28, + "endLine": 27, + "endColumn": 37, + "snippet": "req.query" + } ] - }, - { - "severity": "Low", - "file": "server.js", - "startLine": 9, - "startColumn": 11, - "endLine": 9, - "endColumn": 20, - "snippet": "express()", - "finding": "Express Not Using Helmet", - "scannerDescription": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n" - }, - { - "severity": "Low", - "file": "public/js/bootstrap.js", - "startLine": 136, - "startColumn": 22, - "endLine": 136, - "endColumn": 35, - "snippet": "Math.random()", - "finding": "Use of Insecure Random", - "scannerDescription": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" - }, - { - "severity": "Low", - "file": "public/js/bootstrap.bundle.js", - "startLine": 135, - "startColumn": 22, - "endLine": 135, - "endColumn": 35, - "snippet": "Math.random()", - "finding": "Use of Insecure Random", - "scannerDescription": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" - } - ], - "errors": null, - "multiScanId": "7d5e4733-3f93-11ef-8147-e610d09d7daa" - } - \ No newline at end of file + ] + }, + { + "severity": "Low", + "file": "server.js", + "startLine": 9, + "startColumn": 11, + "endLine": 9, + "endColumn": 20, + "snippet": "express()", + "finding": "Express Not Using Helmet", + "scannerDescription": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n" + }, + { + "severity": "Low", + "file": "public/js/bootstrap.js", + "startLine": 136, + "startColumn": 22, + "endLine": 136, + "endColumn": 35, + "snippet": "Math.random()", + "finding": "Use of Insecure Random", + "scannerDescription": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" + }, + { + "severity": "Low", + "file": "public/js/bootstrap.bundle.js", + "startLine": 135, + "startColumn": 22, + "endLine": 135, + "endColumn": 35, + "snippet": "Math.random()", + "finding": "Use of Insecure Random", + "scannerDescription": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" + } + ], + "errors": null, + "multiScanId": "7d5e4733-3f93-11ef-8147-e610d09d7daa" +} \ No newline at end of file diff --git a/tests/testdata/other/output/formats/audit_summary.json b/tests/testdata/other/output/formats/audit_summary.json index e69de29b..d0da55a1 100644 --- a/tests/testdata/other/output/formats/audit_summary.json +++ b/tests/testdata/other/output/formats/audit_summary.json @@ -0,0 +1,36 @@ +{ + "scans": [ + { + "target": "/Users/user/ejs-frog-demo", + "vulnerabilities": { + "sca": { + "sca": { + "Critical": { + "Applicable": 3 + }, + "High": { + "Not Applicable": 2 + }, + "Medium": { + "Applicable": 1, + "Not Applicable": 2, + "Not Covered": 3 + }, + "Unknown": { + "Not Covered": 1 + } + }, + "unique_findings": 12 + }, + "iac": {}, + "secrets": { + "Medium": 5 + }, + "sast": { + "High": 1, + "Low": 3 + } + } + } + ] +} \ No newline at end of file diff --git a/utils/results/common.go b/utils/results/common.go index fc5588b6..f0b3a013 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -288,6 +288,9 @@ func convertCves(cves []services.Cve) []formats.CveRow { // FindMaxCVEScore returns the maximum CVSS score of the given CVEs or score based on severity and applicability status if not exists. func FindMaxCVEScore(severity severityutils.Severity, applicabilityStatus jasutils.ApplicabilityStatus, cves []formats.CveRow) (string, error) { + if len(cves) == 0 { + return fmt.Sprintf("%.1f", severityutils.GetSeverityScore(severity, applicabilityStatus)), nil + } maxCve := severityutils.MinCveScore for _, cve := range cves { cveScore, err := GetCveScore(severity, applicabilityStatus, cve) diff --git a/utils/results/common_test.go b/utils/results/common_test.go index c567aa9d..ce4d979e 100644 --- a/utils/results/common_test.go +++ b/utils/results/common_test.go @@ -101,14 +101,14 @@ func TestGetIssueIdentifier(t *testing.T) { { name: "Multiple CVEs", cves: []formats.CveRow{{Id: "CVE-2022-1234"}, {Id: "CVE-2019-1234"}}, - delimiter: ",", + delimiter: ", ", issueId: "XRAY-123456", expectedOutput: "CVE-2022-1234, CVE-2019-1234", }, { name: "No CVEs", cves: nil, - delimiter: ",", + delimiter: ", ", issueId: "XRAY-123456", expectedOutput: "XRAY-123456", }, @@ -421,150 +421,6 @@ func TestAppendUniqueImpactPaths(t *testing.T) { // } func TestGetApplicableCveValue(t *testing.T) { - // testCases := []struct { - // name string - // scanResults *ExtendedScanResults - // cves []services.Cve - // expectedResult jasutils.ApplicabilityStatus - // expectedCves []formats.CveRow - // }{ - // { - // name: "not entitled for jas", - // scanResults: &ExtendedScanResults{EntitledForJas: false}, - // expectedResult: jasutils.NotScanned, - // }, - // { - // name: "no cves", - // scanResults: &ExtendedScanResults{ - // ApplicabilityScanResults: []*sarif.Run{ - // sarifutils.CreateRunWithDummyResults( - // sarifutils.CreateResultWithOneLocation("fileName1", 0, 1, 0, 0, "snippet1", "applic_testCve1", "info"), - // sarifutils.CreateDummyPassingResult("applic_testCve2"), - // ), - // }, - // EntitledForJas: true, - // }, - // cves: nil, - // expectedResult: jasutils.NotCovered, - // expectedCves: nil, - // }, - // { - // name: "applicable cve", - // scanResults: &ExtendedScanResults{ - // ApplicabilityScanResults: []*sarif.Run{ - // sarifutils.CreateRunWithDummyResults( - // sarifutils.CreateDummyPassingResult("applic_testCve1"), - // sarifutils.CreateResultWithOneLocation("fileName2", 1, 0, 0, 0, "snippet2", "applic_testCve2", "warning"), - // ), - // }, - // EntitledForJas: true, - // }, - // cves: []services.Cve{{Id: "testCve2"}}, - // expectedResult: jasutils.Applicable, - // expectedCves: []formats.CveRow{{Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.Applicable)}}}, - // }, - // { - // name: "undetermined cve", - // scanResults: &ExtendedScanResults{ - // ApplicabilityScanResults: []*sarif.Run{ - // sarifutils.CreateRunWithDummyResults( - // sarifutils.CreateDummyPassingResult("applic_testCve1"), - // sarifutils.CreateResultWithOneLocation("fileName3", 0, 1, 0, 0, "snippet3", "applic_testCve2", "info"), - // ), - // }, - // EntitledForJas: true, - // }, - // cves: []services.Cve{{Id: "testCve3"}}, - // expectedResult: jasutils.ApplicabilityUndetermined, - // expectedCves: []formats.CveRow{{Id: "testCve3"}}, - // }, - // { - // name: "not applicable cve", - // scanResults: &ExtendedScanResults{ - // ApplicabilityScanResults: []*sarif.Run{ - // sarifutils.CreateRunWithDummyResults( - // sarifutils.CreateDummyPassingResult("applic_testCve1"), - // sarifutils.CreateDummyPassingResult("applic_testCve2"), - // ), - // }, - // EntitledForJas: true, - // }, - // cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - // expectedResult: jasutils.NotApplicable, - // expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}}, - // }, - // { - // name: "applicable and not applicable cves", - // scanResults: &ExtendedScanResults{ - // ApplicabilityScanResults: []*sarif.Run{ - // sarifutils.CreateRunWithDummyResults( - // sarifutils.CreateDummyPassingResult("applic_testCve1"), - // sarifutils.CreateResultWithOneLocation("fileName4", 1, 0, 0, 0, "snippet", "applic_testCve2", "warning"), - // ), - // }, - // EntitledForJas: true, - // }, - // cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - // expectedResult: jasutils.Applicable, - // expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.Applicable)}}}, - // }, - // { - // name: "undetermined and not applicable cves", - // scanResults: &ExtendedScanResults{ - // ApplicabilityScanResults: []*sarif.Run{ - // sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyPassingResult("applic_testCve1")), - // }, - // EntitledForJas: true}, - // cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - // expectedResult: jasutils.ApplicabilityUndetermined, - // expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, {Id: "testCve2"}}, - // }, - // { - // name: "new scan statuses - applicable wins all statuses", - // scanResults: &ExtendedScanResults{ - // ApplicabilityScanResults: []*sarif.Run{ - // sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", sarifutils.CreateDummyPassingResult("applic_testCve1")), - // sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_testCve2")), - // sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve3")), - // }, - // EntitledForJas: true}, - // cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}, {Id: "testCve3"}}, - // expectedResult: jasutils.Applicable, - // expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.Applicable)}}, - // {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, - // {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.NotCovered)}}, - // }, - // }, - // { - // name: "new scan statuses - not covered wins not applicable", - // scanResults: &ExtendedScanResults{ - // ApplicabilityScanResults: []*sarif.Run{ - // sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve1")), - // sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_testCve2")), - // }, - // EntitledForJas: true}, - // cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - // expectedResult: jasutils.NotCovered, - // expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotCovered)}}, - // {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, - // }, - // }, - // { - // name: "new scan statuses - undetermined wins not covered", - // scanResults: &ExtendedScanResults{ - // ApplicabilityScanResults: []*sarif.Run{ - // sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve1")), - // sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "undetermined", sarifutils.CreateDummyPassingResult("applic_testCve2")), - // }, - // EntitledForJas: true}, - // cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - // expectedResult: jasutils.ApplicabilityUndetermined, - // expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotCovered)}}, - // {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.ApplicabilityUndetermined)}}, - // }, - // }, - // } - testCases := []struct { name string entitledForJas bool @@ -603,7 +459,13 @@ func TestGetApplicableCveValue(t *testing.T) { }, cves: []services.Cve{{Id: "testCve2"}}, expectedResult: jasutils.Applicable, - expectedCves: []formats.CveRow{{Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.Applicable)}}}, + expectedCves: []formats.CveRow{{Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.Applicable), Evidence: []formats.Evidence{{ + Location: formats.Location{ + File: "fileName2", + StartLine: 1, + Snippet: "snippet2", + }, + }}}}}, }, { name: "undetermined cve", @@ -642,7 +504,12 @@ func TestGetApplicableCveValue(t *testing.T) { }, cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, expectedResult: jasutils.Applicable, - expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.Applicable)}}}, + expectedCves: []formats.CveRow{ + {Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, + {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.Applicable), + Evidence: []formats.Evidence{{Location: formats.Location{File: "fileName4", StartLine: 1, Snippet: "snippet"}}}, + }}, + }, }, { name: "undetermined and not applicable cves", @@ -709,32 +576,34 @@ func TestGetApplicableCveValue(t *testing.T) { }, cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, components: map[string]services.Component{ - "npm://protobufjs:6.11.2": services.Component{ImpactPaths: [][]services.ImpactPathNode{{services.ImpactPathNode{FullPath: "fileName4", ComponentId: "npm://mquery:3.2.2"}}}}, + "npm://protobufjs:6.11.2": {ImpactPaths: [][]services.ImpactPathNode{{services.ImpactPathNode{FullPath: "fileName4", ComponentId: "npm://mquery:3.2.2"}}}}, "npm://mquery:3.2.2": {}, }, expectedResult: jasutils.Applicable, expectedCves: []formats.CveRow{ {Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, - {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.Applicable)}}, + {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.Applicable), Evidence: []formats.Evidence{{Location: formats.Location{File: "fileName4", StartLine: 1, Snippet: "snippet"}}}}}, }, }, } for _, testCase := range testCases { - cves := convertCves(testCase.cves) - for i := range cves { - cves[i].Applicability = GetCveApplicabilityField(cves[i].Id, testCase.applicabilityScanResults, testCase.components) - } - applicableValue := GetApplicableCveStatus(testCase.entitledForJas, testCase.applicabilityScanResults, cves) - assert.Equal(t, testCase.expectedResult, applicableValue) - if assert.True(t, len(testCase.expectedCves) == len(cves)) { + t.Run(testCase.name, func(t *testing.T) { + cves := convertCves(testCase.cves) for i := range cves { - if testCase.expectedCves[i].Applicability != nil && assert.NotNil(t, cves[i].Applicability) { - assert.Equal(t, testCase.expectedCves[i].Applicability.Status, cves[i].Applicability.Status) - assert.ElementsMatch(t, testCase.expectedCves[i].Applicability.Evidence, cves[i].Applicability.Evidence) + cves[i].Applicability = GetCveApplicabilityField(cves[i].Id, testCase.applicabilityScanResults, testCase.components) + } + applicableValue := GetApplicableCveStatus(testCase.entitledForJas, testCase.applicabilityScanResults, cves) + assert.Equal(t, testCase.expectedResult, applicableValue) + if assert.True(t, len(testCase.expectedCves) == len(cves)) { + for i := range cves { + if testCase.expectedCves[i].Applicability != nil && assert.NotNil(t, cves[i].Applicability) { + assert.Equal(t, testCase.expectedCves[i].Applicability.Status, cves[i].Applicability.Status) + assert.ElementsMatch(t, testCase.expectedCves[i].Applicability.Evidence, cves[i].Applicability.Evidence) + } } } - } + }) } } @@ -790,37 +659,21 @@ func TestGetDirectComponents(t *testing.T) { expectedConvImpactPaths: [][]formats.ComponentRow{{{Name: "jfrog:pack", Version: "1.2.3"}}}, }, { - name: "one direct component with target", - target: filepath.Join("root", "dir", "file"), - impactPaths: [][]services.ImpactPathNode{{ - services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, - services.ImpactPathNode{ComponentId: "gav://jfrog:pack2:1.2.3"}, - }}, - expectedDirectComponentRows: []formats.ComponentRow{{Name: "jfrog:pack1", Version: "1.2.3", Location: &formats.Location{File: filepath.Join("root", "dir", "file")}}}, + name: "one direct component with target", + target: filepath.Join("root", "dir", "file"), + impactPaths: [][]services.ImpactPathNode{{services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack2:1.2.3"}}}, + expectedDirectComponentRows: []formats.ComponentRow{{Name: "jfrog:pack2", Version: "1.2.3", Location: &formats.Location{File: filepath.Join("root", "dir", "file")}}}, expectedConvImpactPaths: [][]formats.ComponentRow{{{Name: "jfrog:pack1", Version: "1.2.3"}, {Name: "jfrog:pack2", Version: "1.2.3"}}}, }, { - name: "multiple direct components", - target: filepath.Join("root", "dir", "file"), - impactPaths: [][]services.ImpactPathNode{ - { - services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, - services.ImpactPathNode{ComponentId: "gav://jfrog:pack2:1.2.3"}, - services.ImpactPathNode{ComponentId: "gav://jfrog:pack3:1.2.3"}, - }, - { - services.ImpactPathNode{ComponentId: "gav://jfrog:pack4:1.2.3"}, - services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, - }, - }, + name: "multiple direct components", + target: filepath.Join("root", "dir", "file"), + impactPaths: [][]services.ImpactPathNode{{services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack21:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack3:1.2.3"}}, {services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack22:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack3:1.2.3"}}}, expectedDirectComponentRows: []formats.ComponentRow{ - {Name: "jfrog:pack1", Version: "1.2.3", Location: &formats.Location{File: filepath.Join("root", "dir", "file")}}, - {Name: "jfrog:pack4", Version: "1.2.3", Location: &formats.Location{File: filepath.Join("root", "dir", "file")}}, - }, - expectedConvImpactPaths: [][]formats.ComponentRow{ - {{Name: "jfrog:pack1", Version: "1.2.3"}, {Name: "jfrog:pack2", Version: "1.2.3"}, {Name: "jfrog:pack3", Version: "1.2.3"}}, - {{Name: "jfrog:pack4", Version: "1.2.3"}, {Name: "jfrog:pack1", Version: "1.2.3"}}, + {Name: "jfrog:pack21", Version: "1.2.3", Location: &formats.Location{File: filepath.Join("root", "dir", "file")}}, + {Name: "jfrog:pack22", Version: "1.2.3", Location: &formats.Location{File: filepath.Join("root", "dir", "file")}}, }, + expectedConvImpactPaths: [][]formats.ComponentRow{{{Name: "jfrog:pack1", Version: "1.2.3"}, {Name: "jfrog:pack21", Version: "1.2.3"}, {Name: "jfrog:pack3", Version: "1.2.3"}}, {{Name: "jfrog:pack1", Version: "1.2.3"}, {Name: "jfrog:pack22", Version: "1.2.3"}, {Name: "jfrog:pack3", Version: "1.2.3"}}}, }, } diff --git a/utils/results/conversion/convertor_test.go b/utils/results/conversion/convertor_test.go index 31dcf456..37c3e789 100644 --- a/utils/results/conversion/convertor_test.go +++ b/utils/results/conversion/convertor_test.go @@ -21,7 +21,6 @@ var ( const ( SimpleJson conversionFormat = "simple-json" Sarif conversionFormat = "sarif" - Table conversionFormat = "table" Summary conversionFormat = "summary" ) @@ -36,7 +35,7 @@ func getValidationParams() validations.ValidationParams { NotApplicable: 7, NotCovered: 4, - Sast: 2, + Sast: 4, Secrets: 5, } } @@ -59,10 +58,6 @@ func TestConvertResults(t *testing.T) { contentFormat: Sarif, expectedContentPath: filepath.Join(testDataDir, "audit_sarif.json"), }, - { - contentFormat: Table, - expectedContentPath: filepath.Join(testDataDir, "audit_table.json"), - }, { contentFormat: Summary, expectedContentPath: filepath.Join(testDataDir, "audit_summary.json"), @@ -79,8 +74,6 @@ func TestConvertResults(t *testing.T) { validateSimpleJsonConversion(t, []byte(utils.ReadOutputFromFile(t, testCase.expectedContentPath)), inputResults, convertor, validationParams) case Sarif: validateSarifConversion(t, []byte(utils.ReadOutputFromFile(t, testCase.expectedContentPath)), inputResults, convertor, validationParams) - case Table: - validateTableConversion(t, []byte(utils.ReadOutputFromFile(t, testCase.expectedContentPath)), inputResults, convertor, validationParams) case Summary: validateSummaryConversion(t, []byte(utils.ReadOutputFromFile(t, testCase.expectedContentPath)), inputResults, convertor, validationParams) } @@ -120,22 +113,6 @@ func validateSarifConversion(t *testing.T, expectedContent []byte, inputResults validations.ValidateCommandSarifOutput(t, validationParams) } -func validateTableConversion(t *testing.T, expectedContent []byte, inputResults *results.SecurityCommandResults, convertor *CommandResultsConvertor, validationParams validations.ValidationParams) { - var expectedResults formats.ResultsTables - if !assert.NoError(t, json.Unmarshal(expectedContent, &expectedResults)) { - return - } - validationParams.Expected = expectedResults - - actualResults, err := convertor.ConvertToTable(inputResults) - if !assert.NoError(t, err) { - return - } - validationParams.Actual = actualResults - - validations.ValidateCommandTableOutput(t, validationParams) -} - func validateSummaryConversion(t *testing.T, expectedContent []byte, inputResults *results.SecurityCommandResults, convertor *CommandResultsConvertor, validationParams validations.ValidationParams) { var expectedResults formats.SummaryResults if !assert.NoError(t, json.Unmarshal(expectedContent, &expectedResults)) { diff --git a/utils/validations/test_validate_summary.go b/utils/validations/test_validate_summary.go index d95afa68..776e2133 100644 --- a/utils/validations/test_validate_summary.go +++ b/utils/validations/test_validate_summary.go @@ -16,7 +16,7 @@ func VerifySummaryResults(t *testing.T, content string, params ValidationParams) err := json.Unmarshal([]byte(content), &results) assert.NoError(t, err) params.Actual = results - ValidateCommandTableOutput(t, params) + ValidateCommandSummaryOutput(t, params) } func ValidateCommandSummaryOutput(t *testing.T, params ValidationParams) { diff --git a/utils/validations/test_validate_table.go b/utils/validations/test_validate_table.go deleted file mode 100644 index 131f1d7d..00000000 --- a/utils/validations/test_validate_table.go +++ /dev/null @@ -1,47 +0,0 @@ -package validations - -import ( - "encoding/json" - "fmt" - "testing" - - "github.com/jfrog/jfrog-cli-security/utils/formats" - "github.com/stretchr/testify/assert" -) - -// Content should be a Json string of formats.ResultsTables and will be unmarshal. -// Value is set as the Actual content in the validation params -func VerifyTableResults(t *testing.T, content string, params ValidationParams) { - var results formats.ResultsTables - err := json.Unmarshal([]byte(content), &results) - assert.NoError(t, err) - params.Actual = results - ValidateCommandTableOutput(t, params) -} - -func ValidateCommandTableOutput(t *testing.T, params ValidationParams) { - results, ok := params.Actual.(formats.ResultsTables) - if assert.True(t, ok) { - ValidateTableIssuesCount(t, params, results) - } -} - -func ValidateTableIssuesCount(t *testing.T, params ValidationParams, results formats.ResultsTables) { - if params.ExactResultsMatch { - assert.Len(t, results.SastTable, params.Sast, fmt.Sprintf("Expected %d sast issues in table, but got %d sast.", params.Sast, len(results.SastTable))) - assert.Len(t, results.SecretsTable, params.Secrets, fmt.Sprintf("Expected %d secrets issues in table, but got %d secrets.", params.Secrets, len(results.SecretsTable))) - assert.Len(t, results.IacTable, params.Iac, fmt.Sprintf("Expected %d IaC issues in table, but got %d IaC.", params.Iac, len(results.IacTable))) - assert.Len(t, results.LicenseViolationsTable, params.LicenseViolations, fmt.Sprintf("Expected %d license issues in table, but got %d license issues.", params.Licenses, len(results.LicenseViolationsTable))) - assert.Len(t, results.LicensesTable, params.Licenses, fmt.Sprintf("Expected %d licenses in table, but got %d licenses.", params.Licenses, len(results.LicensesTable))) - assert.Len(t, results.OperationalRiskViolationsTable, params.OperationalViolations, fmt.Sprintf("Expected %d operational risk issues in table, but got %d operational risk issues.", params.OperationalViolations, len(results.OperationalRiskViolationsTable))) - assert.Equal(t, params.Vulnerabilities+params.SecurityViolations, len(results.SecurityVulnerabilitiesTable), fmt.Sprintf("Expected %d vulnerabilities in table, but got %d vulnerabilities.", params.Vulnerabilities, len(results.SecurityVulnerabilitiesTable))) - return - } - assert.GreaterOrEqual(t, len(results.SastTable), params.Sast, fmt.Sprintf("Expected at least %d sast issues in table, but got %d sast.", params.Sast, len(results.SastTable))) - assert.GreaterOrEqual(t, len(results.SecretsTable), params.Secrets, fmt.Sprintf("Expected at least %d secrets issues in table, but got %d secrets.", params.Secrets, len(results.SecretsTable))) - assert.GreaterOrEqual(t, len(results.IacTable), params.Iac, fmt.Sprintf("Expected at least %d IaC issues in table, but got %d IaC.", params.Iac, len(results.IacTable))) - assert.GreaterOrEqual(t, len(results.LicenseViolationsTable), params.LicenseViolations, fmt.Sprintf("Expected at least %d license issues in table, but got %d license issues.", params.Licenses, len(results.LicenseViolationsTable))) - assert.GreaterOrEqual(t, len(results.LicensesTable), params.Licenses, fmt.Sprintf("Expected at least %d licenses in table, but got %d licenses.", params.Licenses, len(results.LicensesTable))) - assert.GreaterOrEqual(t, len(results.OperationalRiskViolationsTable), params.OperationalViolations, fmt.Sprintf("Expected at least %d operational risk issues in table, but got %d operational risk issues.", params.OperationalViolations, len(results.OperationalRiskViolationsTable))) - assert.GreaterOrEqual(t, len(results.SecurityVulnerabilitiesTable), params.Vulnerabilities+params.SecurityViolations, fmt.Sprintf("Expected at least %d vulnerabilities in table, but got %d vulnerabilities.", params.Vulnerabilities, len(results.SecurityVulnerabilitiesTable))) -} From 2f7f3197741bfefa86a90fa2c617f419496e169f Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 16 Jul 2024 15:34:51 +0300 Subject: [PATCH 25/82] fix tests --- utils/validations/test_validate_sarif.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index 30f9fc7c..299848bf 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -19,9 +19,9 @@ func VerifySarifResults(t *testing.T, content string, params ValidationParams) { } func ValidateCommandSarifOutput(t *testing.T, params ValidationParams) { - results, ok := params.Actual.(sarif.Report) + results, ok := params.Actual.(*sarif.Report) if assert.True(t, ok) { - ValidateSarifIssuesCount(t, params, &results) + ValidateSarifIssuesCount(t, params, results) // if params.Expected != nil { // expectedResults, ok := params.Expected.(sarif.Report) // if assert.True(t, ok) { From a5c66f0b6b5ea5e2afcdfd92e313259e57e30644 Mon Sep 17 00:00:00 2001 From: attiasas Date: Thu, 18 Jul 2024 09:43:50 +0300 Subject: [PATCH 26/82] verify sarif --- .../other/output/formats/audit_sarif.json | 2410 +++++++++-------- utils/formats/sarifutils/sarifutils.go | 8 + utils/jasutils/jasutils.go | 1 + utils/results/common.go | 4 +- .../conversion/sarifparser/sarifparser.go | 46 +- utils/validations/test_validate_sarif.go | 124 +- 6 files changed, 1374 insertions(+), 1219 deletions(-) diff --git a/tests/testdata/other/output/formats/audit_sarif.json b/tests/testdata/other/output/formats/audit_sarif.json index a7879001..701dc586 100644 --- a/tests/testdata/other/output/formats/audit_sarif.json +++ b/tests/testdata/other/output/formats/audit_sarif.json @@ -1,1291 +1,1389 @@ { - "version": "2.1.0", - "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", - "runs": [ - { - "tool": { - "driver": { - "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sca", - "name": "JFrog Xray SCA", - "rules": [ - { - "id": "CVE-2023-29827_ejs_3.1.6", - "shortDescription": { - "text": "[CVE-2023-29827] ejs 3.1.6" - }, - "help": { - "text": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Applicable | `ejs 3.1.6` | No fix available |" - }, - "properties": { - "security-severity": "9.8" - } - }, - { - "id": "CVE-2018-3721_lodash_4.17.0", - "shortDescription": { - "text": "[CVE-2018-3721] lodash 4.17.0" - }, - "help": { - "text": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.5] |" - }, - "properties": { - "security-severity": "6.5" - } - }, - { - "id": "CVE-2024-29041_express_4.18.2", - "shortDescription": { - "text": "[CVE-2024-29041] express 4.18.2" - }, - "help": { - "text": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.1 | Not Covered | `express 4.18.2` | [4.19.2], [5.0.0-beta.3] |" - }, - "properties": { - "security-severity": "6.1" - } - }, - { - "id": "CVE-2019-1010266_lodash_4.17.0", - "shortDescription": { - "text": "[CVE-2019-1010266] lodash 4.17.0" - }, - "help": { - "text": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.11] |" - }, - "properties": { - "security-severity": "6.5" - } + "version": "2.1.0", + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "runs": [ + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Secrets scanner", + "rules": [ + { + "id": "REQ.SECRET.GENERIC.TEXT", + "name": "REQ.SECRET.GENERIC.TEXT", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.TEXT" }, - { - "id": "CVE-2024-39249_async_3.2.4", - "shortDescription": { - "text": "[CVE-2024-39249] async 3.2.4" - }, - "help": { - "text": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Not Covered | `ejs 3.1.6` | No fix available |" - }, - "properties": { - "security-severity": "0.0" - } + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" }, - { - "id": "CVE-2022-29078_ejs_3.1.6", - "shortDescription": { - "text": "[CVE-2022-29078] ejs 3.1.6" - }, - "help": { - "text": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Not Applicable | `ejs 3.1.6` | [3.1.7] |" - }, - "properties": { - "security-severity": "9.8" - } + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.GENERIC.CODE", + "name": "REQ.SECRET.GENERIC.CODE", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.CODE" }, - { - "id": "CVE-2019-10744_lodash_4.17.0", - "shortDescription": { - "text": "[CVE-2019-10744] lodash 4.17.0" - }, - "help": { - "text": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.1 | Not Applicable | `lodash 4.17.0` | [4.17.12] |" - }, - "properties": { - "security-severity": "9.1" - } + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" }, - { - "id": "CVE-2021-23337_lodash_4.17.0", - "shortDescription": { - "text": "[CVE-2021-23337] lodash 4.17.0" - }, - "help": { - "text": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.2 | Not Applicable | `lodash 4.17.0` | [4.17.21] |" - }, - "properties": { - "security-severity": "7.2" - } + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.GENERIC.URL", + "name": "REQ.SECRET.GENERIC.URL", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.URL" }, - { - "id": "CVE-2020-8203_lodash_4.17.0", - "shortDescription": { - "text": "[CVE-2020-8203] lodash 4.17.0" - }, - "help": { - "text": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.4 | Not Applicable | `lodash 4.17.0` | [4.17.19] |" - }, - "properties": { - "security-severity": "7.4" - } + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" }, - { - "id": "CVE-2024-33883_ejs_3.1.6", - "shortDescription": { - "text": "[CVE-2024-33883] ejs 3.1.6" - }, - "help": { - "text": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Not Applicable | `ejs 3.1.6` | [3.1.10] |" - }, - "properties": { - "security-severity": "0.0" - } + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.KEYS", + "name": "REQ.SECRET.KEYS", + "shortDescription": { + "text": "Scanner for REQ.SECRET.KEYS" }, - { - "id": "CVE-2018-16487_lodash_4.17.0", - "shortDescription": { - "text": "[CVE-2018-16487] lodash 4.17.0" - }, - "help": { - "text": "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.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.6 | Not Applicable | `lodash 4.17.0` | [4.17.11] |" - }, - "properties": { - "security-severity": "5.6" - } + "fullDescription": { + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" }, - { - "id": "CVE-2020-28500_lodash_4.17.0", - "shortDescription": { - "text": "[CVE-2020-28500] lodash 4.17.0" - }, - "help": { - "text": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.3 | Not Applicable | `lodash 4.17.0` | [4.17.21] |" - }, - "properties": { - "security-severity": "5.3" - } + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": 6.9 } - ], - "version": "3.98.2" + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721283016-528285823/Secrets_1721283016/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" } - }, - "results": [ - { - "ruleId": "CVE-2023-29827_ejs_3.1.6", - "ruleIndex": 0, - "level": "error", - "message": { - "text": "[CVE-2023-29827] ejs 3.1.6" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file://package.json" + } + ], + "results": [ + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + }, + "region": { + "startLine": 1, + "startColumn": 0, + "endLine": 1, + "endColumn": 0, + "snippet": { + "text": "AKI************" } } } - ] + } + ] + }, + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" }, - { - "ruleId": "CVE-2018-3721_lodash_4.17.0", - "ruleIndex": 1, - "level": "warning", - "message": { - "text": "[CVE-2018-3721] lodash 4.17.0" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file://package.json" + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + }, + "region": { + "startLine": 2, + "startColumn": 0, + "endLine": 2, + "endColumn": 0, + "snippet": { + "text": "Sqc************" } } } - ] + } + ] + }, + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" }, - { - "ruleId": "CVE-2024-29041_express_4.18.2", - "ruleIndex": 2, - "level": "warning", - "message": { - "text": "[CVE-2024-29041] express 4.18.2" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file://package.json" + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + }, + "region": { + "startLine": 3, + "startColumn": 0, + "endLine": 3, + "endColumn": 0, + "snippet": { + "text": "gho************" } } } - ] + } + ] + }, + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" }, - { - "ruleId": "CVE-2019-1010266_lodash_4.17.0", - "ruleIndex": 3, - "level": "warning", - "message": { - "text": "[CVE-2019-1010266] lodash 4.17.0" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file://package.json" + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 10, + "startColumn": 15, + "endLine": 10, + "endColumn": 15, + "snippet": { + "text": "AKI************" } } } - ] + } + ] + }, + { + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" }, - { - "ruleId": "CVE-2024-39249_async_3.2.4", - "ruleIndex": 4, - "level": "none", - "message": { - "text": "[CVE-2024-39249] ejs 3.1.6" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file://package.json" + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 11, + "startColumn": 12, + "endLine": 11, + "endColumn": 12, + "snippet": { + "text": "\"Sq************" } } } - ] - }, - { - "ruleId": "CVE-2022-29078_ejs_3.1.6", - "ruleIndex": 5, - "level": "error", - "message": { - "text": "[CVE-2022-29078] ejs 3.1.6" + } + ] + } + ] + }, + { + "tool": { + "driver": { + "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/infrastructure-as-code-iac", + "name": "JFrog Terraform scanner", + "rules": [], + "version": "1.8.3" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/assafa/.jfrog/dependencies/analyzerManager/iac_scanner/tf_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721283016-528285823/IaC_1721283029/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [] + }, + { + "tool": { + "driver": { + "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sast", + "name": "USAF", + "rules": [ + { + "id": "js-express-without-helmet", + "shortDescription": { + "text": "Express Not Using Helmet" + }, + "fullDescription": { + "text": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n", + "markdown": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n" + }, + "properties": { + "security-severity": 3.9 + } }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file://package.json" + { + "id": "js-insecure-random", + "shortDescription": { + "text": "Use of Insecure Random" + }, + "fullDescription": { + "text": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n", + "markdown": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" + }, + "defaultConfiguration": { + "parameters": { + "properties": { + "CWE": "338" } } + }, + "properties": { + "security-severity": 3.9 } - ] - }, - { - "ruleId": "CVE-2019-10744_lodash_4.17.0", - "ruleIndex": 6, - "level": "error", - "message": { - "text": "[CVE-2019-10744] lodash 4.17.0" }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file://package.json" + { + "id": "js-template-injection", + "shortDescription": { + "text": "Template Object Injection" + }, + "fullDescription": { + "text": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n", + "markdown": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n" + }, + "defaultConfiguration": { + "parameters": { + "properties": { + "CWE": "73" } } + }, + "properties": { + "security-severity": 8.9 } - ] + } + ], + "version": "1.8.3" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/assafa/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721283016-528285823/Sast_1721283031/results.sarif", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721283016-528285823/Sast_1721283031/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [ + { + "ruleId": "js-insecure-random", + "level": "note", + "message": { + "text": "Use of Insecure Random" }, - { - "ruleId": "CVE-2021-23337_lodash_4.17.0", - "ruleIndex": 7, - "level": "error", - "message": { - "text": "[CVE-2021-23337] lodash 4.17.0" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file://package.json" + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" + }, + "region": { + "startLine": 136, + "startColumn": 22, + "endLine": 136, + "endColumn": 35, + "snippet": { + "text": "Math.random()" } } - } - ] + }, + "logicalLocations": [ + { + "fullyQualifiedName": "public.js.bootstrap.^_0.Util.getUID" + } + ] + } + ] + }, + { + "ruleId": "js-insecure-random", + "level": "note", + "message": { + "text": "Use of Insecure Random" }, - { - "ruleId": "CVE-2020-8203_lodash_4.17.0", - "ruleIndex": 8, - "level": "error", - "message": { - "text": "[CVE-2020-8203] lodash 4.17.0" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file://package.json" + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + }, + "region": { + "startLine": 135, + "startColumn": 22, + "endLine": 135, + "endColumn": 35, + "snippet": { + "text": "Math.random()" } } - } - ] + }, + "logicalLocations": [ + { + "fullyQualifiedName": "public.js.bootstrap\u003cdot\u003ebundle.^_0.Util.getUID" + } + ] + } + ] + }, + { + "ruleId": "js-express-without-helmet", + "level": "note", + "message": { + "text": "Express Not Using Helmet" }, - { - "ruleId": "CVE-2024-33883_ejs_3.1.6", - "ruleIndex": 9, - "level": "warning", - "message": { - "text": "[CVE-2024-33883] ejs 3.1.6" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file://package.json" + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 8, + "startColumn": 11, + "endLine": 8, + "endColumn": 20, + "snippet": { + "text": "express()" } } - } - ] + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server" + } + ] + } + ] + }, + { + "ruleId": "js-template-injection", + "level": "error", + "message": { + "text": "Template Object Injection" }, - { - "ruleId": "CVE-2018-16487_lodash_4.17.0", - "ruleIndex": 10, - "level": "warning", - "message": { - "text": "[CVE-2018-16487] lodash 4.17.0" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file://package.json" + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 26, + "startColumn": 28, + "endLine": 26, + "endColumn": 37, + "snippet": { + "text": "req.query" } } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 21, + "startColumn": 23, + "endLine": 21, + "endColumn": 26, + "snippet": { + "text": "req" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 26, + "startColumn": 28, + "endLine": 26, + "endColumn": 31, + "snippet": { + "text": "req" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 26, + "startColumn": 28, + "endLine": 26, + "endColumn": 37, + "snippet": { + "text": "req.query" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + } + ] + } + ] + } + ] + } + ] + }, + { + "tool": { + "driver": { + "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sca", + "name": "JFrog Xray SCA", + "rules": [ + { + "id": "CVE-2022-29078_ejs_3.1.6", + "shortDescription": { + "text": "[CVE-2022-29078] ejs 3.1.6" + }, + "help": { + "text": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Applicable | `ejs 3.1.6` | [3.1.7] |" + }, + "properties": { + "security-severity": "9.8" } - ] - }, - { - "ruleId": "CVE-2020-28500_lodash_4.17.0", - "ruleIndex": 11, - "level": "warning", - "message": { - "text": "[CVE-2020-28500] lodash 4.17.0" }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file://package.json" - } - } + { + "id": "CVE-2020-8203_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2020-8203] lodash 4.17.0" + }, + "help": { + "text": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.4 | Not Applicable | `lodash 4.17.0` | [4.17.19] |" + }, + "properties": { + "security-severity": "7.4" } - ] - } - ] - }, - { - "tool": { - "driver": { - "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", - "name": "JFrog Applicability Scanner", - "rules": [ - { - "id": "applic_CVE-2018-16487", - "name": "CVE-2018-16487", - "shortDescription": { - "text": "Scanner for CVE-2018-16487" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", - "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } + }, + { + "id": "CVE-2019-10744_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2019-10744] lodash 4.17.0" }, - { - "id": "applic_CVE-2019-10744", - "name": "CVE-2019-10744", - "shortDescription": { - "text": "Scanner for CVE-2019-10744" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present.", - "markdown": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } + "help": { + "text": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.1 | Applicable | `lodash 4.17.0` | [4.17.12] |" }, - { - "id": "applic_CVE-2020-28500", - "name": "CVE-2020-28500", - "shortDescription": { - "text": "Scanner for CVE-2020-28500" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument.", - "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } + "properties": { + "security-severity": "9.1" + } + }, + { + "id": "CVE-2020-28500_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2020-28500] lodash 4.17.0" }, - { - "id": "applic_CVE-2020-8203", - "name": "CVE-2020-8203", - "shortDescription": { - "text": "Scanner for CVE-2020-8203" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present.", - "markdown": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } + "help": { + "text": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.3 | Not Applicable | `lodash 4.17.0` | [4.17.21] |" }, - { - "id": "applic_CVE-2021-23337", - "name": "CVE-2021-23337", - "shortDescription": { - "text": "Scanner for CVE-2021-23337" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument.", - "markdown": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } + "properties": { + "security-severity": "5.3" + } + }, + { + "id": "CVE-2021-23337_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2021-23337] lodash 4.17.0" }, - { - "id": "applic_CVE-2022-29078", - "name": "CVE-2022-29078", - "shortDescription": { - "text": "Scanner for CVE-2022-29078" - }, - "fullDescription": { - "text": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", - "markdown": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } + "help": { + "text": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.2 | Not Applicable | `lodash 4.17.0` | [4.17.21] |" }, - { - "id": "applic_CVE-2024-33883", - "name": "CVE-2024-33883", - "shortDescription": { - "text": "Scanner for CVE-2024-33883" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable function `ejs.compile()` is called.", - "markdown": "The scanner checks whether the vulnerable function `ejs.compile()` is called." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } + "properties": { + "security-severity": "7.2" + } + }, + { + "id": "CVE-2018-16487_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2018-16487] lodash 4.17.0" }, - { - "id": "applic_CVE-2023-29827", - "name": "CVE-2023-29827", - "shortDescription": { - "text": "Scanner for CVE-2023-29827" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`", - "markdown": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`" - }, - "properties": { - "applicability": "applicable", - "conclusion": "negative", - "security-severity": "6.9" - } + "help": { + "text": "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.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.6 | Applicable | `lodash 4.17.0` | [4.17.11] |" }, - { - "id": "applic_CVE-2018-3721", - "name": "CVE-2018-3721", - "shortDescription": { - "text": "Scanner for uncovered CVE-2018-3721" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } + "properties": { + "security-severity": "5.6" + } + }, + { + "id": "CVE-2024-39249_async_3.2.4", + "shortDescription": { + "text": "[CVE-2024-39249] async 3.2.4" }, - { - "id": "applic_CVE-2019-1010266", - "name": "CVE-2019-1010266", - "shortDescription": { - "text": "Scanner for uncovered CVE-2019-1010266" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } + "help": { + "text": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Not Covered | `ejs 3.1.6` | No fix available |" }, - { - "id": "applic_CVE-2024-29041", - "name": "CVE-2024-29041", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-29041" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } + "properties": { + "security-severity": "0.0" + } + }, + { + "id": "CVE-2023-29827_ejs_3.1.6", + "shortDescription": { + "text": "[CVE-2023-29827] ejs 3.1.6" }, - { - "id": "applic_CVE-2024-39249", - "name": "CVE-2024-39249", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-39249" - }, - "fullDescription": { - "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", - "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." - }, - "properties": { - "applicability": "not_covered", - "security-severity": "6.9" - } + "help": { + "text": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Applicable | `ejs 3.1.6` | No fix available |" }, - { - "id": "applic_CVE-2024-39249", - "name": "CVE-2024-39249", - "shortDescription": { - "text": "Scanner for indirect dependency CVE-2024-39249" - }, - "fullDescription": { - "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", - "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." - }, - "properties": { - "applicability": "not_applicable" - } + "properties": { + "security-severity": "9.8" } - ], - "version": "1.0" - } - }, - "invocations": [ - { - "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", - "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720708975-4044569217/Applicability_1720708983/config.yaml" - ], - "executionSuccessful": true, - "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" - } - } - ], - "results": [ - { - "ruleId": "applic_CVE-2018-16487", - "message": { - "text": "Prototype pollution `Object.freeze` remediation was detected" }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 1, - "startColumn": 0, - "endLine": 1, - "endColumn": 31, - "snippet": { - "text": "Object.freeze(Object.prototype)" - } - } - } + { + "id": "CVE-2024-29041_express_4.18.2", + "shortDescription": { + "text": "[CVE-2024-29041] express 4.18.2" + }, + "help": { + "text": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.1 | Not Covered | `express 4.18.2` | [4.19.2], [5.0.0-beta.3] |" + }, + "properties": { + "security-severity": "6.1" + } + }, + { + "id": "CVE-2018-3721_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2018-3721] lodash 4.17.0" + }, + "help": { + "text": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.5] |" + }, + "properties": { + "security-severity": "6.5" + } + }, + { + "id": "CVE-2024-33883_ejs_3.1.6", + "shortDescription": { + "text": "[CVE-2024-33883] ejs 3.1.6" + }, + "help": { + "text": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.9 | Not Applicable | `ejs 3.1.6` | [3.1.10] |" + }, + "properties": { + "security-severity": "6.9" + } + }, + { + "id": "CVE-2019-1010266_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2019-1010266] lodash 4.17.0" + }, + "help": { + "text": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.11] |" + }, + "properties": { + "security-severity": "6.5" } - ] - }, - { - "ruleId": "applic_CVE-2018-16487", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." } + ], + "version": "3.98.5" + } + }, + "results": [ + { + "properties": { + "applicability": "Not Covered", + "fixedVersion": "No fix available" }, - { - "ruleId": "applic_CVE-2019-10744", - "message": { - "text": "Prototype pollution `Object.freeze` remediation was detected" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 1, - "startColumn": 0, - "endLine": 1, - "endColumn": 31, - "snippet": { - "text": "Object.freeze(Object.prototype)" - } - } + "ruleId": "CVE-2024-39249_async_3.2.4", + "ruleIndex": 6, + "level": "none", + "message": { + "text": "[CVE-2024-39249] ejs 3.1.6" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo" } } - ] - }, - { - "ruleId": "applic_CVE-2019-10744", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." } + ] + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "[3.1.10]" + }, + "ruleId": "CVE-2024-33883_ejs_3.1.6", + "ruleIndex": 10, + "level": "warning", + "message": { + "text": "[CVE-2024-33883] ejs 3.1.6" }, - { - "ruleId": "applic_CVE-2020-28500", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo" + } + } } + ] + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2023-29827_ejs_3.1.6", + "ruleIndex": 7, + "level": "error", + "message": { + "text": "[CVE-2023-29827] ejs 3.1.6" }, - { - "ruleId": "applic_CVE-2020-8203", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo" + } + } } + ] + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "[3.1.7]" }, - { - "ruleId": "applic_CVE-2021-23337", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." + "ruleId": "CVE-2022-29078_ejs_3.1.6", + "ruleIndex": 0, + "level": "error", + "message": { + "text": "[CVE-2022-29078] ejs 3.1.6" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo" + } + } } + ] + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "[4.17.19]" }, - { - "ruleId": "applic_CVE-2022-29078", - "message": { - "text": "Prototype pollution `Object.freeze` remediation was detected" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 1, - "startColumn": 0, - "endLine": 1, - "endColumn": 31, - "snippet": { - "text": "Object.freeze(Object.prototype)" - } - } + "ruleId": "CVE-2020-8203_lodash_4.17.0", + "ruleIndex": 1, + "level": "error", + "message": { + "text": "[CVE-2020-8203] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo" } } - ] + } + ] + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "[4.17.12]" }, - { - "ruleId": "applic_CVE-2022-29078", - "kind": "pass", - "message": { - "text": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + "ruleId": "CVE-2019-10744_lodash_4.17.0", + "ruleIndex": 2, + "level": "error", + "message": { + "text": "[CVE-2019-10744] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo" + } + } } + ] + }, + { + "properties": { + "applicability": "Not Covered", + "fixedVersion": "[4.17.11]" + }, + "ruleId": "CVE-2019-1010266_lodash_4.17.0", + "ruleIndex": 11, + "level": "warning", + "message": { + "text": "[CVE-2019-1010266] lodash 4.17.0" }, - { - "ruleId": "applic_CVE-2024-33883", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable function `ejs.compile()` is called." + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo" + } + } } + ] + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "[4.17.21]" }, - { - "ruleId": "applic_CVE-2023-29827", - "message": { - "text": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 15, - "startColumn": 0, - "endLine": 15, - "endColumn": 29, - "snippet": { - "text": "app.set('view engine', 'ejs')" - } - } + "ruleId": "CVE-2020-28500_lodash_4.17.0", + "ruleIndex": 3, + "level": "warning", + "message": { + "text": "[CVE-2020-28500] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo" } } - ] + } + ] + }, + { + "properties": { + "applicability": "Not Covered", + "fixedVersion": "[4.17.5]" }, - { - "ruleId": "applic_CVE-2023-29827", - "message": { - "text": "The vulnerable function render is called" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 27, - "startColumn": 2, - "endLine": 27, - "endColumn": 37, - "snippet": { - "text": "res.render('pages/index',req.query)" - } - } + "ruleId": "CVE-2018-3721_lodash_4.17.0", + "ruleIndex": 9, + "level": "warning", + "message": { + "text": "[CVE-2018-3721] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo" } } - ] + } + ] + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "[4.17.21]" + }, + "ruleId": "CVE-2021-23337_lodash_4.17.0", + "ruleIndex": 4, + "level": "error", + "message": { + "text": "[CVE-2021-23337] lodash 4.17.0" }, - { - "ruleId": "applic_CVE-2024-39249", - "kind": "pass", - "message": { - "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo" + } + } } - } - ] - }, - { - "tool": { - "driver": { - "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/infrastructure-as-code-iac", - "name": "JFrog Terraform scanner", - "rules": [], - "version": "1.8.3" - } + ] }, - "invocations": [ - { - "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/iac_scanner/tf_scanner", - "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720708975-4044569217/IaC_1720708975/config.yaml" - ], - "executionSuccessful": true, - "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "[4.17.11]" + }, + "ruleId": "CVE-2018-16487_lodash_4.17.0", + "ruleIndex": 5, + "level": "warning", + "message": { + "text": "[CVE-2018-16487] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo" + } + } } - } - ], - "results": [] - }, - { - "tool": { - "driver": { - "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", - "name": "JFrog Secrets scanner", - "rules": [ - { - "id": "REQ.SECRET.GENERIC.TEXT", - "name": "REQ.SECRET.GENERIC.TEXT", - "shortDescription": { - "text": "Scanner for REQ.SECRET.GENERIC.TEXT" - }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive" + ] + }, + { + "properties": { + "applicability": "Not Covered", + "fixedVersion": "[4.19.2], [5.0.0-beta.3]" + }, + "ruleId": "CVE-2024-29041_express_4.18.2", + "ruleIndex": 8, + "level": "warning", + "message": { + "text": "[CVE-2024-29041] express 4.18.2" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo" } + } + } + ] + } + ] + }, + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Applicability Scanner", + "rules": [ + { + "id": "applic_CVE-2018-16487", + "name": "CVE-2018-16487", + "shortDescription": { + "text": "Scanner for CVE-2018-16487" }, - { - "id": "REQ.SECRET.GENERIC.CODE", - "name": "REQ.SECRET.GENERIC.CODE", - "shortDescription": { - "text": "Scanner for REQ.SECRET.GENERIC.CODE" - }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive" - } + "fullDescription": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." }, - { - "id": "REQ.SECRET.GENERIC.URL", - "name": "REQ.SECRET.GENERIC.URL", - "shortDescription": { - "text": "Scanner for REQ.SECRET.GENERIC.URL" - }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive" - } + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": 6.9 + } + }, + { + "id": "applic_CVE-2019-10744", + "name": "CVE-2019-10744", + "shortDescription": { + "text": "Scanner for CVE-2019-10744" }, - { - "id": "REQ.SECRET.KEYS", - "name": "REQ.SECRET.KEYS", - "shortDescription": { - "text": "Scanner for REQ.SECRET.KEYS" - }, - "fullDescription": { - "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", - "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" - }, - "properties": { - "applicability": "applicable", - "conclusion": "negative", - "security-severity": "6.9" - } + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": 6.9 } - ], - "version": "1.0" - } - }, - "invocations": [ - { - "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", - "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720708975-4044569217/Secrets_1720708975/config.yaml" - ], - "executionSuccessful": true, - "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" - } - } - ], - "results": [ - { - "ruleId": "REQ.SECRET.KEYS", - "message": { - "text": "Secret keys were found" }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" - }, - "region": { - "startLine": 1, - "startColumn": 0, - "endLine": 1, - "endColumn": 0, - "snippet": { - "text": "AKI************" - } - } - } + { + "id": "applic_CVE-2020-28500", + "name": "CVE-2020-28500", + "shortDescription": { + "text": "Scanner for CVE-2020-28500" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument.", + "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": 6.9 } - ] - }, - { - "ruleId": "REQ.SECRET.KEYS", - "message": { - "text": "Secret keys were found" }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" - }, - "region": { - "startLine": 2, - "startColumn": 0, - "endLine": 2, - "endColumn": 0, - "snippet": { - "text": "Sqc************" - } - } - } + { + "id": "applic_CVE-2020-8203", + "name": "CVE-2020-8203", + "shortDescription": { + "text": "Scanner for CVE-2020-8203" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": 6.9 } - ] - }, - { - "ruleId": "REQ.SECRET.KEYS", - "message": { - "text": "Secret keys were found" }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" - }, - "region": { - "startLine": 3, - "startColumn": 0, - "endLine": 3, - "endColumn": 0, - "snippet": { - "text": "gho************" - } - } - } + { + "id": "applic_CVE-2021-23337", + "name": "CVE-2021-23337", + "shortDescription": { + "text": "Scanner for CVE-2021-23337" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument.", + "markdown": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": 6.9 } - ] - }, - { - "ruleId": "REQ.SECRET.KEYS", - "message": { - "text": "Secret keys were found" }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 11, - "startColumn": 15, - "endLine": 11, - "endColumn": 15, - "snippet": { - "text": "AKI************" - } + { + "id": "applic_CVE-2022-29078", + "name": "CVE-2022-29078", + "shortDescription": { + "text": "Scanner for CVE-2022-29078" + }, + "fullDescription": { + "text": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": 6.9 + } + }, + { + "id": "applic_CVE-2024-33883", + "name": "CVE-2024-33883", + "shortDescription": { + "text": "Scanner for CVE-2024-33883" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `ejs.compile()` is called.", + "markdown": "The scanner checks whether the vulnerable function `ejs.compile()` is called." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": 6.9 + } + }, + { + "id": "applic_CVE-2023-29827", + "name": "CVE-2023-29827", + "shortDescription": { + "text": "Scanner for CVE-2023-29827" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`", + "markdown": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": 6.9 + } + }, + { + "id": "applic_CVE-2018-3721", + "name": "CVE-2018-3721", + "shortDescription": { + "text": "Scanner for uncovered CVE-2018-3721" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-29041", + "name": "CVE-2024-29041", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-29041" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2019-1010266", + "name": "CVE-2019-1010266", + "shortDescription": { + "text": "Scanner for uncovered CVE-2019-1010266" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-39249", + "name": "CVE-2024-39249", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-39249" + }, + "fullDescription": { + "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", + "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + }, + "properties": { + "applicability": "not_covered", + "security-severity": 6.9 + } + }, + { + "id": "applic_CVE-2024-39249", + "name": "CVE-2024-39249", + "shortDescription": { + "text": "Scanner for indirect dependency CVE-2024-39249" + }, + "fullDescription": { + "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", + "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + }, + "properties": { + "applicability": "not_applicable" + } + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721283016-528285823/Applicability_1721283031/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [ + { + "ruleId": "applic_CVE-2018-16487", + "message": { + "text": "The vulnerable function merge/mergeWith/defaultsDeep is called with external input" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 33, + "startColumn": 2, + "endLine": 33, + "endColumn": 34, + "snippet": { + "text": "lodash.defaultsDeep(data, input)" } } } - ] + } + ] + }, + { + "ruleId": "applic_CVE-2018-16487", + "message": { + "text": "The vulnerable function merge/mergeWith/defaultsDeep is called with external input" }, - { - "ruleId": "REQ.SECRET.KEYS", - "message": { - "text": "Secret keys were found" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 12, - "startColumn": 12, - "endLine": 12, - "endColumn": 12, - "snippet": { - "text": "\"Sq************" - } + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 6, + "startColumn": 0, + "endLine": 6, + "endColumn": 32, + "snippet": { + "text": "lodash.defaultsDeep({}, evilsrc)" } } } - ] - } - ] - }, - { - "tool": { - "driver": { - "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sast", - "name": "USAF", - "rules": [ - { - "id": "js-express-without-helmet", - "shortDescription": { - "text": "Express Not Using Helmet" - }, - "fullDescription": { - "text": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n", - "markdown": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n" - }, - "properties": { - "security-severity": "3.9" - } - }, - { - "id": "js-insecure-random", - "shortDescription": { - "text": "Use of Insecure Random" - }, - "fullDescription": { - "text": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n", - "markdown": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" - }, - "defaultConfiguration": { - "parameters": { - "properties": { - "CWE": "338" - } + } + ] + }, + { + "ruleId": "applic_CVE-2019-10744", + "message": { + "text": "The vulnerable function defaultsDeep is called with external input" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 33, + "startColumn": 2, + "endLine": 33, + "endColumn": 34, + "snippet": { + "text": "lodash.defaultsDeep(data, input)" } - }, - "properties": { - "security-severity": "3.9" } - }, - { - "id": "js-template-injection", - "shortDescription": { - "text": "Template Object Injection" - }, - "fullDescription": { - "text": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n", - "markdown": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n" - }, - "defaultConfiguration": { - "parameters": { - "properties": { - "CWE": "73" - } + } + } + ] + }, + { + "ruleId": "applic_CVE-2019-10744", + "message": { + "text": "The vulnerable function defaultsDeep is called with external input" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 6, + "startColumn": 0, + "endLine": 6, + "endColumn": 32, + "snippet": { + "text": "lodash.defaultsDeep({}, evilsrc)" } - }, - "properties": { - "security-severity": "8.9" } } - ], - "version": "1.8.3" + } + ] + }, + { + "ruleId": "applic_CVE-2020-28500", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." } }, - "invocations": [ - { - "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", - "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720708975-4044569217/Sast_1720708982/results.sarif", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720708975-4044569217/Sast_1720708982/config.yaml" - ], - "executionSuccessful": true, - "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" - } + { + "ruleId": "applic_CVE-2020-8203", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." } - ], - "results": [ - { - "ruleId": "js-insecure-random", - "level": "note", - "message": { - "text": "Use of Insecure Random" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" - }, - "region": { - "startLine": 136, - "startColumn": 22, - "endLine": 136, - "endColumn": 35, - "snippet": { - "text": "Math.random()" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "public.js.bootstrap.^_0.Util.getUID" - } - ] - } - ] + }, + { + "ruleId": "applic_CVE-2021-23337", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." + } + }, + { + "ruleId": "applic_CVE-2022-29078", + "message": { + "text": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" }, - { - "ruleId": "js-insecure-random", - "level": "note", - "message": { - "text": "Use of Insecure Random" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" - }, - "region": { - "startLine": 135, - "startColumn": 22, - "endLine": 135, - "endColumn": 35, - "snippet": { - "text": "Math.random()" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "public.js.bootstrap\u003cdot\u003ebundle.^_0.Util.getUID" + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 14, + "startColumn": 0, + "endLine": 14, + "endColumn": 29, + "snippet": { + "text": "app.set('view engine', 'ejs')" } - ] + } } - ] + } + ] + }, + { + "ruleId": "applic_CVE-2022-29078", + "message": { + "text": "The vulnerable function render is called" }, - { - "ruleId": "js-express-without-helmet", - "level": "note", - "message": { - "text": "Express Not Using Helmet" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 9, - "startColumn": 11, - "endLine": 9, - "endColumn": 20, - "snippet": { - "text": "express()" - } + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 26, + "startColumn": 2, + "endLine": 26, + "endColumn": 37, + "snippet": { + "text": "res.render('pages/index',req.query)" } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "server" - } - ] + } } - ] + } + ] + }, + { + "ruleId": "applic_CVE-2024-33883", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `ejs.compile()` is called." + } + }, + { + "ruleId": "applic_CVE-2023-29827", + "message": { + "text": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" }, - { - "ruleId": "js-template-injection", - "level": "error", - "message": { - "text": "Template Object Injection" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 27, - "startColumn": 28, - "endLine": 27, - "endColumn": 37, - "snippet": { - "text": "req.query" - } + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 14, + "startColumn": 0, + "endLine": 14, + "endColumn": 29, + "snippet": { + "text": "app.set('view engine', 'ejs')" } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "server.^_4" - } - ] + } } - ], - "codeFlows": [ - { - "threadFlows": [ - { - "locations": [ - { - "location": { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 22, - "startColumn": 23, - "endLine": 22, - "endColumn": 26, - "snippet": { - "text": "req" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "server.^_4" - } - ] - } - }, - { - "location": { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 27, - "startColumn": 28, - "endLine": 27, - "endColumn": 31, - "snippet": { - "text": "req" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "server.^_4" - } - ] - } - }, - { - "location": { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 27, - "startColumn": 28, - "endLine": 27, - "endColumn": 37, - "snippet": { - "text": "req.query" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "server.^_4" - } - ] - } - } - ] + } + ] + }, + { + "ruleId": "applic_CVE-2023-29827", + "message": { + "text": "The vulnerable function render is called" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 26, + "startColumn": 2, + "endLine": 26, + "endColumn": 37, + "snippet": { + "text": "res.render('pages/index',req.query)" } - ] + } } - ] + } + ] + }, + { + "ruleId": "applic_CVE-2024-39249", + "kind": "pass", + "message": { + "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." } - ] - } - ] - } - \ No newline at end of file + } + ] + } + ] +} \ No newline at end of file diff --git a/utils/formats/sarifutils/sarifutils.go b/utils/formats/sarifutils/sarifutils.go index 493043d0..0e7e3046 100644 --- a/utils/formats/sarifutils/sarifutils.go +++ b/utils/formats/sarifutils/sarifutils.go @@ -110,7 +110,15 @@ func GetRunsByWorkingDirectory(workingDirectory string, runs ...*sarif.Run) (fil } } return +} +func GetRunsByToolName(report *sarif.Report, toolName string) (filteredRuns []*sarif.Run) { + for _, run := range report.Runs { + if run.Tool.Driver != nil && run.Tool.Driver.Name == toolName { + filteredRuns = append(filteredRuns, run) + } + } + return } func GetResultMsgText(result *sarif.Result) string { diff --git a/utils/jasutils/jasutils.go b/utils/jasutils/jasutils.go index a6861252..3f699770 100644 --- a/utils/jasutils/jasutils.go +++ b/utils/jasutils/jasutils.go @@ -8,6 +8,7 @@ import ( const ( ApplicabilityRuleIdPrefix = "applic_" + ApplicabilitySarifPropertyKey = "applicability" ) const ( diff --git a/utils/results/common.go b/utils/results/common.go index f0b3a013..cde62242 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -519,8 +519,8 @@ func GetApplicableCveStatus(entitledForJas bool, applicabilityScanResults []*sar } func getApplicabilityStatusFromRule(rule *sarif.ReportingDescriptor) jasutils.ApplicabilityStatus { - if rule.Properties["applicability"] != nil { - status, ok := rule.Properties["applicability"].(string) + if rule.Properties[jasutils.ApplicabilitySarifPropertyKey] != nil { + status, ok := rule.Properties[jasutils.ApplicabilitySarifPropertyKey].(string) if !ok { log.Debug(fmt.Sprintf("Failed to get applicability status from rule properties for rule_id %s", rule.ID)) } diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index 01186198..ddccbe6a 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -17,7 +17,14 @@ import ( ) const ( - ScaToolName = "JFrog Xray SCA" + FixedVersionSarifPropertyKey = "fixedVersion" + WatchSarifPropertyKey = "watch" + + ScaToolName = "JFrog Xray SCA" + SastToolName = "USAF" + IacToolName = "JFrog Terraform scanner" + SecretsToolName = "JFrog Secrets scanner" + ContexualAnalysisToolName = "JFrog Applicability Scanner" ) type CmdResultsSarifConverter struct { @@ -275,10 +282,12 @@ func addSarifScaLicenseViolation(sarifResults *[]*sarif.Result, rules *map[strin } } -func parseScaToSarifFormat(xrayId, summary, markdownDescription, cveScore string, generateTitleFunc func(depName string, version string, issueId string) string, cves []formats.CveRow, severity severityutils.Severity, _ jasutils.ApplicabilityStatus, impactedPackagesName, impactedPackagesVersion string, _ []string, directComponents []formats.ComponentRow) (sarifResults []*sarif.Result, rule *sarif.ReportingDescriptor) { +func parseScaToSarifFormat(xrayId, summary, markdownDescription, cveScore string, generateTitleFunc func(depName string, version string, issueId string) string, cves []formats.CveRow, severity severityutils.Severity, applicabilityStatus jasutils.ApplicabilityStatus, impactedPackagesName, impactedPackagesVersion string, fixedVersions []string, directComponents []formats.ComponentRow, watches ...string) (sarifResults []*sarif.Result, rule *sarif.ReportingDescriptor) { + // General information issueId := results.GetIssueIdentifier(cves, xrayId, "_") cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, issueId) - // Add rule if not exists + level := severityutils.SeverityToSarifSeverityLevel(severity) + // Add rule fpr the cve if not exists rule = getScaIssueSarifRule( cveImpactedComponentRuleId, generateTitleFunc(impactedPackagesName, impactedPackagesVersion, issueId), @@ -286,14 +295,23 @@ func parseScaToSarifFormat(xrayId, summary, markdownDescription, cveScore string summary, markdownDescription, ) - // Add result for each component - level := severityutils.SeverityToSarifSeverityLevel(severity) for _, directDependency := range directComponents { - msg := generateTitleFunc(directDependency.Name, directDependency.Version, issueId) - issueLocation := getComponentSarifLocation(directDependency) + // Create result for each direct dependency issueResult := sarif.NewRuleResult(cveImpactedComponentRuleId). - WithMessage(sarif.NewTextMessage(msg)). + WithMessage(sarif.NewTextMessage(generateTitleFunc(directDependency.Name, directDependency.Version, issueId))). WithLevel(level.String()) + // Add properties + resultsProperties := sarif.NewPropertyBag() + if applicabilityStatus != jasutils.NotScanned { + resultsProperties.Add(jasutils.ApplicabilitySarifPropertyKey, applicabilityStatus.String()) + } + if len(watches) > 0 { + resultsProperties.Add(WatchSarifPropertyKey, strings.Join(watches, ", ")) + } + resultsProperties.Add(FixedVersionSarifPropertyKey, getFixedVersionString(fixedVersions)) + issueResult.AttachPropertyBag(resultsProperties) + // Add location + issueLocation := getComponentSarifLocation(directDependency) if issueLocation != nil { issueResult.AddLocation(issueLocation) } @@ -336,10 +354,7 @@ func getScaIssueMarkdownDescription(directDependencies []formats.ComponentRow, c if err != nil { return "", err } - descriptionFixVersions := "No fix available" - if len(fixedVersions) > 0 { - descriptionFixVersions = strings.Join(fixedVersions, ", ") - } + descriptionFixVersions := getFixedVersionString(fixedVersions) if applicableStatus == jasutils.NotScanned { return fmt.Sprintf("| Severity Score | Direct Dependencies | Fixed Versions |\n| :---: | :----: | :---: |\n| %s | %s | %s |", cveScore, formattedDirectDependencies, descriptionFixVersions), nil @@ -348,6 +363,13 @@ func getScaIssueMarkdownDescription(directDependencies []formats.ComponentRow, c cveScore, applicableStatus.String(), formattedDirectDependencies, descriptionFixVersions), nil } +func getFixedVersionString(fixedVersions []string) string { + if len(fixedVersions) == 0 { + return "No fix available" + } + return strings.Join(fixedVersions, ", ") +} + func getDirectDependenciesFormatted(directDependencies []formats.ComponentRow) (string, error) { var formattedDirectDependencies strings.Builder for _, dependency := range directDependencies { diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index 299848bf..d1574380 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -2,8 +2,12 @@ package validations import ( "encoding/json" + "strings" "testing" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/results/conversion/sarifparser" "github.com/owenrumney/go-sarif/v2/sarif" "github.com/stretchr/testify/assert" ) @@ -32,55 +36,77 @@ func ValidateCommandSarifOutput(t *testing.T, params ValidationParams) { } func ValidateSarifIssuesCount(t *testing.T, params ValidationParams, results *sarif.Report) { - // var sast, iac, secrets, licenseViolations, applicableResults, undeterminedResults, notCoveredResults, notApplicableResults int - // for _, run := range results.Runs { - // for _, result := range run.Results { - - // } - // } - - // for _, vuln := range results.Vulnerabilities { - // switch vuln.Applicable { - // case string(jasutils.NotApplicable): - // notApplicableResults++ - // case string(jasutils.Applicable): - // applicableResults++ - // case string(jasutils.NotCovered): - // notCoveredResults++ - // case string(jasutils.ApplicabilityUndetermined): - // undeterminedResults++ - // } - // } - - // if params.ExactResultsMatch { - // assert.Equal(t, params.Sast, len(results.Sast), "Expected %d sast in scan responses, but got %d sast.", params.Sast, len(results.Sast)) - // assert.Equal(t, params.Secrets, len(results.Secrets), "Expected %d secrets in scan responses, but got %d secrets.", params.Secrets, len(results.Secrets)) - // assert.Equal(t, params.Iac, len(results.Iacs), "Expected %d IaC in scan responses, but got %d IaC.", params.Iac, len(results.Iacs)) - - // assert.Equal(t, params.Applicable, applicableResults, "Expected %d applicable vulnerabilities in scan responses, but got %d applicable vulnerabilities.", params.Applicable, applicableResults) - // assert.Equal(t, params.Undetermined, undeterminedResults, "Expected %d undetermined vulnerabilities in scan responses, but got %d undetermined vulnerabilities.", params.Undetermined, undeterminedResults) - // assert.Equal(t, params.NotCovered, notCoveredResults, "Expected %d not covered vulnerabilities in scan responses, but got %d not covered vulnerabilities.", params.NotCovered, notCoveredResults) - // assert.Equal(t, params.NotApplicable, notApplicableResults, "Expected %d not applicable vulnerabilities in scan responses, but got %d not applicable vulnerabilities.", params.NotApplicable, notApplicableResults) - - // assert.Equal(t, params.SecurityViolations, len(results.SecurityViolations), "Expected %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, len(results.SecurityViolations)) - // assert.Equal(t, params.LicenseViolations, len(results.LicensesViolations), "Expected %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, len(results.LicensesViolations)) - // assert.Equal(t, params.OperationalViolations, len(results.OperationalRiskViolations), "Expected %d operational risk violations in scan responses, but got %d operational risk violations.", params.OperationalViolations, len(results.OperationalRiskViolations)) - - // assert.Equal(t, params.Licenses, len(results.Licenses), "Expected %d Licenses in scan responses, but got %d Licenses.", params.Licenses, len(results.Licenses)) - // } else { - // assert.GreaterOrEqual(t, len(results.Sast), params.Sast, "Expected at least %d sast in scan responses, but got %d sast.", params.Sast, len(results.Sast)) - // assert.GreaterOrEqual(t, len(results.Secrets), params.Secrets, "Expected at least %d secrets in scan responses, but got %d secrets.", params.Secrets, len(results.Secrets)) - // assert.GreaterOrEqual(t, len(results.Iacs), params.Iac, "Expected at least %d IaC in scan responses, but got %d IaC.", params.Iac, len(results.Iacs)) + var vulnerabilities, securityViolations, licenseViolations, applicableResults, undeterminedResults, notCoveredResults, notApplicableResults int + + iac := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, sarifparser.IacToolName)...) + secrets := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, sarifparser.SecretsToolName)...) + sast := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, sarifparser.SastToolName)...) + + scaRuns := sarifutils.GetRunsByToolName(results, sarifparser.ScaToolName) + for _, run := range scaRuns { + for _, result := range run.Results { + // If watch property exists, add to security violations or license violations else add to vulnerabilities + if _, ok := result.Properties[sarifparser.WatchSarifPropertyKey]; ok { + if isSecurityIssue(result) { + securityViolations++ + } else { + licenseViolations++ + // No more work needed for license violations + continue + } + } else { + vulnerabilities++ + } + // Get the applicability status in the result properties (convert to string) and add count to the appropriate category + applicabilityProperty := result.Properties[jasutils.ApplicabilitySarifPropertyKey] + if applicability, ok := applicabilityProperty.(string); ok { + switch applicability { + case jasutils.Applicable.String(): + applicableResults++ + case jasutils.NotApplicable.String(): + notApplicableResults++ + case jasutils.ApplicabilityUndetermined.String(): + undeterminedResults++ + case jasutils.NotCovered.String(): + notCoveredResults++ + } + } + } + } - // assert.GreaterOrEqual(t, applicableResults, params.Applicable, "Expected at least %d applicable vulnerabilities in scan responses, but got %d applicable vulnerabilities.", params.Applicable, applicableResults) - // assert.GreaterOrEqual(t, undeterminedResults, params.Undetermined, "Expected at least %d undetermined vulnerabilities in scan responses, but got %d undetermined vulnerabilities.", params.Undetermined, undeterminedResults) - // assert.GreaterOrEqual(t, notCoveredResults, params.NotCovered, "Expected at least %d not covered vulnerabilities in scan responses, but got %d not covered vulnerabilities.", params.NotCovered, notCoveredResults) - // assert.GreaterOrEqual(t, notApplicableResults, params.NotApplicable, "Expected at least %d not applicable vulnerabilities in scan responses, but got %d not applicable vulnerabilities.", params.NotApplicable, notApplicableResults) + if params.ExactResultsMatch { + assert.Equal(t, params.Sast, sast, "Expected %d sast in scan responses, but got %d sast.", params.Sast, sast) + assert.Equal(t, params.Secrets, secrets, "Expected %d secrets in scan responses, but got %d secrets.", params.Secrets, secrets) + assert.Equal(t, params.Iac, iac, "Expected %d IaC in scan responses, but got %d IaC.", params.Iac, iac) + assert.Equal(t, params.Applicable, applicableResults, "Expected %d applicable results in scan responses, but got %d applicable results.", params.Applicable, applicableResults) + assert.Equal(t, params.Undetermined, undeterminedResults, "Expected %d undetermined results in scan responses, but got %d undetermined results.", params.Undetermined, undeterminedResults) + assert.Equal(t, params.NotCovered, notCoveredResults, "Expected %d not covered results in scan responses, but got %d not covered results.", params.NotCovered, notCoveredResults) + assert.Equal(t, params.NotApplicable, notApplicableResults, "Expected %d not applicable results in scan responses, but got %d not applicable results.", params.NotApplicable, notApplicableResults) + assert.Equal(t, params.SecurityViolations, securityViolations, "Expected %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, securityViolations) + assert.Equal(t, params.LicenseViolations, licenseViolations, "Expected %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, licenseViolations) + assert.Equal(t, params.Vulnerabilities, vulnerabilities, "Expected %d vulnerabilities in scan responses, but got %d vulnerabilities.", params.Vulnerabilities, vulnerabilities) + } else { + assert.GreaterOrEqual(t, sast, params.Sast, "Expected at least %d sast in scan responses, but got %d sast.", params.Sast, sast) + assert.GreaterOrEqual(t, secrets, params.Secrets, "Expected at least %d secrets in scan responses, but got %d secrets.", params.Secrets, secrets) + assert.GreaterOrEqual(t, iac, params.Iac, "Expected at least %d IaC in scan responses, but got %d IaC.", params.Iac, iac) + assert.GreaterOrEqual(t, applicableResults, params.Applicable, "Expected at least %d applicable results in scan responses, but got %d applicable results.", params.Applicable, applicableResults) + assert.GreaterOrEqual(t, undeterminedResults, params.Undetermined, "Expected at least %d undetermined results in scan responses, but got %d undetermined results.", params.Undetermined, undeterminedResults) + assert.GreaterOrEqual(t, notCoveredResults, params.NotCovered, "Expected at least %d not covered results in scan responses, but got %d not covered results.", params.NotCovered, notCoveredResults) + assert.GreaterOrEqual(t, notApplicableResults, params.NotApplicable, "Expected at least %d not applicable results in scan responses, but got %d not applicable results.", params.NotApplicable, notApplicableResults) + assert.GreaterOrEqual(t, securityViolations, params.SecurityViolations, "Expected at least %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, securityViolations) + assert.GreaterOrEqual(t, licenseViolations, params.LicenseViolations, "Expected at least %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, licenseViolations) + } +} - // assert.GreaterOrEqual(t, len(results.SecurityViolations), params.SecurityViolations, "Expected at least %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, len(results.SecurityViolations)) - // assert.GreaterOrEqual(t, len(results.LicensesViolations), params.LicenseViolations, "Expected at least %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, len(results.LicensesViolations)) - // assert.GreaterOrEqual(t, len(results.OperationalRiskViolations), params.OperationalViolations, "Expected at least %d operational risk violations in scan responses, but got %d operational risk violations.", params.OperationalViolations, len(results.OperationalRiskViolations)) +func isSecurityIssue(result *sarif.Result) bool { + // If the rule id starts with CVE or XRAY, it is a security issue + if result.RuleID == nil { + return false + } + ruleID := *result.RuleID - // assert.GreaterOrEqual(t, len(results.Licenses), params.Licenses, "Expected at least %d Licenses in scan responses, but got %d Licenses.", params.Licenses, len(results.Licenses)) - // } -} + if strings.HasPrefix(ruleID, "CVE") || strings.HasPrefix(ruleID, "XRAY") { + return true + } + return false +} \ No newline at end of file From 20f24b4bc40058367bb43a0a262771b8a6a54ae7 Mon Sep 17 00:00:00 2001 From: attiasas Date: Thu, 18 Jul 2024 10:57:58 +0300 Subject: [PATCH 27/82] fix merge --- commands/enrich/enrich.go | 76 ++++++++++--------- tests/utils/test_utils.go | 2 +- utils/jasutils/jasutils.go | 2 +- .../conversion/sarifparser/sarifparser.go | 2 +- utils/validations/test_validate_sarif.go | 6 +- 5 files changed, 45 insertions(+), 43 deletions(-) diff --git a/commands/enrich/enrich.go b/commands/enrich/enrich.go index 5fb0071a..d0606c46 100644 --- a/commands/enrich/enrich.go +++ b/commands/enrich/enrich.go @@ -5,15 +5,20 @@ import ( "encoding/xml" "errors" "fmt" + "os" + "os/exec" + "path/filepath" + "github.com/beevik/etree" "github.com/jfrog/gofrog/parallel" "github.com/jfrog/jfrog-cli-core/v2/common/spec" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-security/commands/enrich/enrichgraph" - "github.com/jfrog/jfrog-cli-security/formats" - "github.com/jfrog/jfrog-cli-security/utils" - xrutils "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/results/output" + "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-cli-security/utils/xray" "github.com/jfrog/jfrog-client-go/artifactory/services/fspatterns" clientutils "github.com/jfrog/jfrog-client-go/utils" @@ -22,18 +27,11 @@ import ( "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "github.com/jfrog/jfrog-client-go/utils/log" "github.com/jfrog/jfrog-client-go/xray/services" - "os" - "os/exec" ) type FileContext func(string) parallel.TaskFunc type indexFileHandlerFunc func(file string) -type ScanInfo struct { - Target string - Result *services.ScanResponse -} - type EnrichCommand struct { serverDetails *config.ServerDetails spec *spec.SpecFiles @@ -64,8 +62,15 @@ func (enrichCmd *EnrichCommand) ServerDetails() (*config.ServerDetails, error) { return enrichCmd.serverDetails, nil } -func AppendVulnsToJson(results *utils.Results) error { - fileName := utils.GetScaScanFileName(results) +func getScaScanFileName(cmdResults *results.SecurityCommandResults) string { + if len(cmdResults.Targets) > 0 { + return cmdResults.Targets[0].Target + } + return "" +} + +func AppendVulnsToJson(cmdResults *results.SecurityCommandResults) error { + fileName := getScaScanFileName(cmdResults) fileContent, err := os.ReadFile(fileName) if err != nil { fmt.Println("Error reading file:", err) @@ -78,7 +83,7 @@ func AppendVulnsToJson(results *utils.Results) error { return err } var vulnerabilities []map[string]string - xrayResults := results.GetScaScansXrayResults()[0] + xrayResults := cmdResults.GetScaScansXrayResults()[0] for _, vuln := range xrayResults.Vulnerabilities { for component := range vuln.Components { vulnerability := map[string]string{"bom-ref": component, "id": vuln.Cves[0].Id} @@ -86,18 +91,18 @@ func AppendVulnsToJson(results *utils.Results) error { } } data["vulnerabilities"] = vulnerabilities - return utils.PrintJson(data) + return output.PrintJson(data) } -func AppendVulnsToXML(results *utils.Results) error { - fileName := utils.GetScaScanFileName(results) +func AppendVulnsToXML(cmdResults *results.SecurityCommandResults) error { + fileName := getScaScanFileName(cmdResults) result := etree.NewDocument() err := result.ReadFromFile(fileName) if err != nil { return err } destination := result.FindElements("//bom")[0] - xrayResults := results.GetScaScansXrayResults()[0] + xrayResults := cmdResults.GetScaScansXrayResults()[0] vulns := destination.CreateElement("vulnerabilities") for _, vuln := range xrayResults.Vulnerabilities { for component := range vuln.Components { @@ -114,7 +119,7 @@ func AppendVulnsToXML(results *utils.Results) error { return nil } -func isXML(scaResults []*utils.ScaScanResult) (bool, error) { +func isXML(scaResults []*results.TargetResults) (bool, error) { if len(scaResults) == 0 { return false, errors.New("unable to retrieve file") } @@ -156,8 +161,8 @@ func (enrichCmd *EnrichCommand) Run() (err error) { threads = enrichCmd.threads } - // resultsArr is a two-dimensional array. Each array in it contains a list of ScanResponses that were requested and collected by a specific thread. - resultsArr := make([][]*ScanInfo, threads) + scanResults := results.NewCommandResults(xrayVersion, false) + fileProducerConsumer := parallel.NewRunner(enrichCmd.threads, 20000, false) fileProducerErrors := make([][]formats.SimpleJsonError, threads) indexedFileProducerConsumer := parallel.NewRunner(enrichCmd.threads, 20000, false) @@ -165,16 +170,9 @@ func (enrichCmd *EnrichCommand) Run() (err error) { fileCollectingErrorsQueue := clientutils.NewErrorsQueue(1) // Start walking on the filesystem to "produce" files that match the given pattern // while the consumer uses the indexer to index those files. - enrichCmd.prepareScanTasks(fileProducerConsumer, indexedFileProducerConsumer, resultsArr, indexedFileProducerErrors, fileCollectingErrorsQueue, xrayVersion) + enrichCmd.prepareScanTasks(fileProducerConsumer, indexedFileProducerConsumer, scanResults, indexedFileProducerErrors, fileCollectingErrorsQueue, xrayVersion) enrichCmd.performScanTasks(fileProducerConsumer, indexedFileProducerConsumer) - // Handle results - var flatResults []*xrutils.ScaScanResult - for _, arr := range resultsArr { - for _, res := range arr { - flatResults = append(flatResults, &xrutils.ScaScanResult{Target: res.Target, XrayResults: []services.ScanResponse{*res.Result}}) - } - } if enrichCmd.progress != nil { if err = enrichCmd.progress.Quit(); err != nil { return err @@ -190,11 +188,9 @@ func (enrichCmd *EnrichCommand) Run() (err error) { scanErrors = appendErrorSlice(scanErrors, fileProducerErrors) scanErrors = appendErrorSlice(scanErrors, indexedFileProducerErrors) - scanResults := xrutils.NewAuditResults() scanResults.XrayVersion = xrayVersion - scanResults.ScaResults = flatResults - isxml, err := isXML(scanResults.ScaResults) + isxml, err := isXML(scanResults.Targets) if err != nil { return } @@ -227,13 +223,13 @@ func (enrichCmd *EnrichCommand) CommandName() string { return "xr_enrich" } -func (enrichCmd *EnrichCommand) prepareScanTasks(fileProducer, indexedFileProducer parallel.Runner, resultsArr [][]*ScanInfo, indexedFileErrors [][]formats.SimpleJsonError, fileCollectingErrorsQueue *clientutils.ErrorsQueue, xrayVersion string) { +func (enrichCmd *EnrichCommand) prepareScanTasks(fileProducer, indexedFileProducer parallel.Runner, cmdResults *results.SecurityCommandResults, indexedFileErrors [][]formats.SimpleJsonError, fileCollectingErrorsQueue *clientutils.ErrorsQueue, xrayVersion string) { go func() { defer fileProducer.Done() // Iterate over file-spec groups and produce indexing tasks. // When encountering an error, log and move to next group. specFiles := enrichCmd.spec.Files - artifactHandlerFunc := enrichCmd.createIndexerHandlerFunc(indexedFileProducer, resultsArr, indexedFileErrors, xrayVersion) + artifactHandlerFunc := enrichCmd.createIndexerHandlerFunc(indexedFileProducer, cmdResults, indexedFileErrors, xrayVersion) taskHandler := getAddTaskToProducerFunc(fileProducer, artifactHandlerFunc) err := FileForEnriching(specFiles[0], taskHandler) @@ -244,14 +240,18 @@ func (enrichCmd *EnrichCommand) prepareScanTasks(fileProducer, indexedFileProduc }() } -func (enrichCmd *EnrichCommand) createIndexerHandlerFunc(indexedFileProducer parallel.Runner, resultsArr [][]*ScanInfo, indexedFileErrors [][]formats.SimpleJsonError, xrayVersion string) FileContext { +func (enrichCmd *EnrichCommand) createIndexerHandlerFunc(indexedFileProducer parallel.Runner, cmdResults *results.SecurityCommandResults, indexedFileErrors [][]formats.SimpleJsonError, xrayVersion string) FileContext { return func(filePath string) parallel.TaskFunc { return func(threadId int) (err error) { // Add a new task to the second producer/consumer // which will send the indexed binary to Xray and then will store the received result. taskFunc := func(threadId int) (err error) { - fileContent, err := os.ReadFile(filePath) + // Create a scan target for the file. + targetResults := cmdResults.NewScanResults(results.ScanTarget{Target: filePath, Name: filepath.Base(filePath)}) + log.Debug(clientutils.GetLogMsgPrefix(threadId, false)+"enrich file:", targetResults.Target) + fileContent, err := os.ReadFile(targetResults.Target) if err != nil { + targetResults.AddError(err) return err } params := &services.XrayGraphImportParams{ @@ -264,14 +264,16 @@ func (enrichCmd *EnrichCommand) createIndexerHandlerFunc(indexedFileProducer par SetXrayVersion(xrayVersion) xrayManager, err := xray.CreateXrayServiceManager(importGraphParams.ServerDetails()) if err != nil { + targetResults.AddError(err) return err } scanResults, err := enrichgraph.RunImportGraphAndGetResults(importGraphParams, xrayManager) if err != nil { - indexedFileErrors[threadId] = append(indexedFileErrors[threadId], formats.SimpleJsonError{FilePath: filePath, ErrorMessage: err.Error()}) + targetResults.AddError(err) return } - resultsArr[threadId] = append(resultsArr[threadId], &ScanInfo{Target: filePath, Result: scanResults}) + targetResults.NewScaScanResults(*scanResults) + targetResults.Technology = techutils.Technology(scanResults.ScannedPackageType) return } diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index 97198774..2f56c2a5 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -5,7 +5,7 @@ import ( "encoding/xml" "errors" "fmt" - "github.com/jfrog/jfrog-cli-security/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats" "os" "path/filepath" "strconv" diff --git a/utils/jasutils/jasutils.go b/utils/jasutils/jasutils.go index 3f699770..ffd10352 100644 --- a/utils/jasutils/jasutils.go +++ b/utils/jasutils/jasutils.go @@ -7,7 +7,7 @@ import ( ) const ( - ApplicabilityRuleIdPrefix = "applic_" + ApplicabilityRuleIdPrefix = "applic_" ApplicabilitySarifPropertyKey = "applicability" ) diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index ddccbe6a..15020dc1 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -18,7 +18,7 @@ import ( const ( FixedVersionSarifPropertyKey = "fixedVersion" - WatchSarifPropertyKey = "watch" + WatchSarifPropertyKey = "watch" ScaToolName = "JFrog Xray SCA" SastToolName = "USAF" diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index d1574380..ac7e2a05 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -37,11 +37,11 @@ func ValidateCommandSarifOutput(t *testing.T, params ValidationParams) { func ValidateSarifIssuesCount(t *testing.T, params ValidationParams, results *sarif.Report) { var vulnerabilities, securityViolations, licenseViolations, applicableResults, undeterminedResults, notCoveredResults, notApplicableResults int - + iac := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, sarifparser.IacToolName)...) secrets := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, sarifparser.SecretsToolName)...) sast := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, sarifparser.SastToolName)...) - + scaRuns := sarifutils.GetRunsByToolName(results, sarifparser.ScaToolName) for _, run := range scaRuns { for _, result := range run.Results { @@ -109,4 +109,4 @@ func isSecurityIssue(result *sarif.Result) bool { return true } return false -} \ No newline at end of file +} From f93cfa08057a0adeee6853a5d2509040b47c142e Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 21 Jul 2024 08:59:22 +0300 Subject: [PATCH 28/82] continue validations --- commands/audit/audit_test.go | 8 +- utils/formats/sarifutils/sarifutils.go | 29 ++ utils/results/common.go | 12 +- .../conversion/sarifparser/sarifparser.go | 11 +- .../sarifparser/sarifparser_test.go | 2 +- .../simplejsonparser/simplejsonparser_test.go | 294 ++++++++++-------- .../results/output/securityJobSummary_test.go | 2 +- utils/results/results.go | 1 + utils/severityutils/severity.go | 11 +- utils/validations/test_validate_sarif.go | 128 +++++++- .../validations/test_validate_simple_json.go | 62 ++-- utils/validations/test_validation.go | 216 ++++++++++--- 12 files changed, 543 insertions(+), 233 deletions(-) diff --git a/commands/audit/audit_test.go b/commands/audit/audit_test.go index 766500bc..542eaa8f 100644 --- a/commands/audit/audit_test.go +++ b/commands/audit/audit_test.go @@ -148,8 +148,12 @@ func TestDetectScansToPreform(t *testing.T) { detectScanTargets(results, test.params()) if assert.Len(t, results.Targets, len(test.expected)) { for i := range results.Targets { - sort.Strings(results.Targets[i].ScaResults.Descriptors) - sort.Strings(test.expected[i].ScaResults.Descriptors) + if results.Targets[i].ScaResults != nil { + sort.Strings(results.Targets[i].ScaResults.Descriptors) + } + if test.expected[i].ScaResults != nil { + sort.Strings(test.expected[i].ScaResults.Descriptors) + } } } assert.ElementsMatch(t, test.expected, results.Targets) diff --git a/utils/formats/sarifutils/sarifutils.go b/utils/formats/sarifutils/sarifutils.go index 0e7e3046..03dd84ea 100644 --- a/utils/formats/sarifutils/sarifutils.go +++ b/utils/formats/sarifutils/sarifutils.go @@ -242,6 +242,35 @@ func GetRuleFullDescription(rule *sarif.ReportingDescriptor) string { return "" } +func GetRuleFullDescriptionMarkdown(rule *sarif.ReportingDescriptor) string { + if rule.FullDescription != nil && rule.FullDescription.Markdown != nil { + return *rule.FullDescription.Markdown + } + return "" + +} + +func GetRuleHelp(rule *sarif.ReportingDescriptor) string { + if rule.Help != nil && rule.Help.Text != nil { + return *rule.Help.Text + } + return "" +} + +func GetRuleHelpMarkdown(rule *sarif.ReportingDescriptor) string { + if rule.Help != nil && rule.Help.Markdown != nil { + return *rule.Help.Markdown + } + return "" +} + +func GetRuleShortDescription(rule *sarif.ReportingDescriptor) string { + if rule.ShortDescription != nil && rule.ShortDescription.Text != nil { + return *rule.ShortDescription.Text + } + return "" +} + func GetRunRules(run *sarif.Run) []*sarif.ReportingDescriptor { if run != nil && run.Tool.Driver != nil { return run.Tool.Driver.Rules diff --git a/utils/results/common.go b/utils/results/common.go index cde62242..9f1ff3b8 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -268,13 +268,15 @@ func GetScaIssueId(depName, version, issueId string) string { func ConvertCvesWithApplicability(cves []services.Cve, entitledForJas bool, applicabilityRuns []*sarif.Run, components map[string]services.Component) (convertedCves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus) { convertedCves = convertCves(cves) + applicabilityStatus = jasutils.NotScanned + if !entitledForJas { + return + } applicabilityStatus = jasutils.ApplicabilityUndetermined - if entitledForJas { - for i := range convertedCves { - convertedCves[i].Applicability = GetCveApplicabilityField(convertedCves[i].Id, applicabilityRuns, components) - } - applicabilityStatus = GetApplicableCveStatus(entitledForJas, applicabilityRuns, convertedCves) + for i := range convertedCves { + convertedCves[i].Applicability = GetCveApplicabilityField(convertedCves[i].Id, applicabilityRuns, components) } + applicabilityStatus = GetApplicableCveStatus(entitledForJas, applicabilityRuns, convertedCves) return } diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index 15020dc1..c3c45c42 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -70,7 +70,7 @@ func (sc *CmdResultsSarifConverter) Reset(_, xrayVersion string, entitledForJas return } -func (sc *CmdResultsSarifConverter) ParseNewScanResultsMetadata(target string, _ ...error) (err error) { +func (sc *CmdResultsSarifConverter) ParseNewScanResultsMetadata(target string, errors ...error) (err error) { if sc.current == nil { return results.ConvertorResetErr } @@ -82,6 +82,11 @@ func (sc *CmdResultsSarifConverter) ParseNewScanResultsMetadata(target string, _ } sc.scaCurrentRun = sarif.NewRunWithInformationURI(ScaToolName, utils.BaseDocumentationURL+"sca") sc.scaCurrentRun.Tool.Driver.Version = &sc.xrayVersion + // Add target as working directory in the run invocation + sc.scaCurrentRun.Invocations = append(sc.scaCurrentRun.Invocations, sarif.NewInvocation(). + WithWorkingDirectory(sarif.NewSimpleArtifactLocation(target)). + WithExecutionSuccess(len(errors) == 0), + ) return } @@ -385,7 +390,7 @@ func getScaIssueSarifHeadline(depName, version, issueId string) string { } func getXrayLicenseSarifHeadline(depName, version, key string) string { - return fmt.Sprintf("License violation [%s] %s %s", key, depName, version) + return fmt.Sprintf("License violation [%s] in %s %s", key, depName, version) } func getLicenseViolationSummary(depName, version, key string) string { @@ -397,5 +402,5 @@ func getScaLicenseViolationMarkdown(depName, version, key string, directDependen if err != nil { return "", err } - return fmt.Sprintf("**The following direct dependencies are utilizing the `%s %s` dependency with `%s` license violation:**\n%s", depName, version, key, formattedDirectDependencies), nil + return fmt.Sprintf("%s
Direct dependencies:
%s", getLicenseViolationSummary(depName, version, key), formattedDirectDependencies), nil } diff --git a/utils/results/conversion/sarifparser/sarifparser_test.go b/utils/results/conversion/sarifparser/sarifparser_test.go index 542a7286..0b450dca 100644 --- a/utils/results/conversion/sarifparser/sarifparser_test.go +++ b/utils/results/conversion/sarifparser/sarifparser_test.go @@ -109,7 +109,7 @@ func TestGetSarifTableDescription(t *testing.T) { cveScore: "3.0", applicableStatus: jasutils.NotCovered, fixedVersions: []string{"3.0.1"}, - expectedDescription: "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.0 | Not covered | `example-package 3.0.0` | 3.0.1 |", + expectedDescription: "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.0 | Not Covered | `example-package 3.0.0` | 3.0.1 |", }, { name: "Undetermined vulnerability", diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go index 925d9641..1d19055d 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go @@ -13,6 +13,100 @@ import ( "github.com/jfrog/jfrog-client-go/xray/services" ) +var ( + testScaScanVulnerabilities = []services.Vulnerability{ + { + IssueId: "XRAY-1", + Summary: "summary-1", + Severity: "High", + Cves: []services.Cve{{Id: "CVE-1"}}, + Components: map[string]services.Component{ + "component-A": { + ImpactPaths: [][]services.ImpactPathNode{{ + {ComponentId: "root"}, + {ComponentId: "component-A"}, + }}, + }, + "component-B": { + ImpactPaths: [][]services.ImpactPathNode{{ + {ComponentId: "root"}, + {ComponentId: "component-B"}, + }}, + }, + }, + }, + { + IssueId: "XRAY-2", + Summary: "summary-2", + Severity: "Low", + Cves: []services.Cve{{Id: "CVE-2"}}, + Components: map[string]services.Component{ + "component-B": { + ImpactPaths: [][]services.ImpactPathNode{{ + {ComponentId: "root"}, + {ComponentId: "component-B"}, + }}, + }, + }, + }, + } + testScaScanViolation = []services.Violation{ + { + IssueId: "XRAY-1", + Summary: "summary-1", + Severity: "High", + WatchName: "watch-name", + ViolationType: "security", + Cves: []services.Cve{{Id: "CVE-1"}}, + Components: map[string]services.Component{ + "component-A": { + ImpactPaths: [][]services.ImpactPathNode{{ + {ComponentId: "root"}, + {ComponentId: "component-A"}, + }}, + }, + "component-B": { + ImpactPaths: [][]services.ImpactPathNode{{ + {ComponentId: "root"}, + {ComponentId: "component-B"}, + }}, + }, + }, + }, + { + IssueId: "XRAY-2", + Summary: "summary-2", + Severity: "Low", + WatchName: "watch-name", + ViolationType: "security", + Cves: []services.Cve{{Id: "CVE-2"}}, + Components: map[string]services.Component{ + "component-B": { + ImpactPaths: [][]services.ImpactPathNode{{ + {ComponentId: "root"}, + {ComponentId: "component-B"}, + }}, + }, + }, + }, + { + IssueId: "XRAY-3", + Summary: "summary-3", + Severity: "Low", + ViolationType: "license", + LicenseKey: "license-1", + Components: map[string]services.Component{ + "component-B": { + ImpactPaths: [][]services.ImpactPathNode{{ + {ComponentId: "root"}, + {ComponentId: "component-B"}, + }}, + }, + }, + }, + } +) + func TestSortVulnerabilityOrViolationRows(t *testing.T) { testCases := []struct { name string @@ -171,81 +265,75 @@ func TestGetOperationalRiskReadableData(t *testing.T) { } func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { - testScaScanResults := []services.Vulnerability{ - { - IssueId: "XRAY-1", - Summary: "summary-1", - Severity: "High", - Cves: []services.Cve{{Id: "CVE-1"}}, - Components: map[string]services.Component{"component-A": {}, "component-B": {}}, - }, - { - IssueId: "XRAY-2", - Summary: "summary-2", - Severity: "Low", - Cves: []services.Cve{{Id: "CVE-2"}}, - Components: map[string]services.Component{"component-B": {}}, - }, - } - testCases := []struct { name string input []services.Vulnerability target string entitledForJas bool - pretty bool applicablityRuns []*sarif.Run expectedOutput []formats.VulnerabilityOrViolationRow }{ { - name: "No vulnerabilities", - input: []services.Vulnerability{}, - target: "target", - entitledForJas: false, - pretty: false, - applicablityRuns: []*sarif.Run{}, - expectedOutput: []formats.VulnerabilityOrViolationRow{}, + name: "No vulnerabilities", + target: "target", }, { - name: "Vulnerabilities with no applicability", - input: testScaScanResults, - target: "target", - entitledForJas: false, - pretty: false, - applicablityRuns: []*sarif.Run{}, + name: "Vulnerabilities not entitled for JAS", + input: testScaScanVulnerabilities, + target: "target", expectedOutput: []formats.VulnerabilityOrViolationRow{ { Summary: "summary-1", IssueId: "XRAY-1", + Cves: []formats.CveRow{{Id: "CVE-1"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High"}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 17}, ImpactedDependencyName: "component-A", + // Direct + Components: []formats.ComponentRow{{ + Name: "component-A", + Location: &formats.Location{File: "target"}, + }}, }, + ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-A"}}}, }, { Summary: "summary-1", IssueId: "XRAY-1", + Cves: []formats.CveRow{{Id: "CVE-1"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High"}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 17}, ImpactedDependencyName: "component-B", + // Direct + Components: []formats.ComponentRow{{ + Name: "component-B", + Location: &formats.Location{File: "target"}, + }}, }, + ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-B"}}}, }, { Summary: "summary-2", IssueId: "XRAY-2", + Cves: []formats.CveRow{{Id: "CVE-2"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low"}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 11}, ImpactedDependencyName: "component-B", + // Direct + Components: []formats.ComponentRow{{ + Name: "component-B", + Location: &formats.Location{File: "target"}, + }}, }, + ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-B"}}}, }, }, }, { - name: "Vulnerabilities with applicability", - input: testScaScanResults, + name: "Vulnerabilities with Jas", + input: testScaScanVulnerabilities, target: "target", entitledForJas: true, - pretty: false, applicablityRuns: []*sarif.Run{ sarifutils.CreateRunWithDummyResults( sarifutils.CreateDummyPassingResult("applic_CVE-1"), @@ -256,79 +344,61 @@ func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { }, expectedOutput: []formats.VulnerabilityOrViolationRow{ { - Summary: "summary-1", - IssueId: "XRAY-1", + Summary: "summary-1", + IssueId: "XRAY-1", + Applicable: jasutils.NotApplicable.String(), + Cves: []formats.CveRow{{Id: "CVE-1", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High"}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 4}, ImpactedDependencyName: "component-A", - Components: []formats.ComponentRow{{Name: "component-A", Location: &formats.Location{File: "target"}}}, + // Direct + Components: []formats.ComponentRow{{ + Name: "component-A", + Location: &formats.Location{File: "target"}, + }}, }, - Applicable: jasutils.NotApplicable.String(), - Cves: []formats.CveRow{{Id: "CVE-1"}}, + ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-A"}}}, }, { - Summary: "summary-1", - IssueId: "XRAY-1", + Summary: "summary-1", + IssueId: "XRAY-1", + Applicable: jasutils.NotApplicable.String(), + Cves: []formats.CveRow{{Id: "CVE-1", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High"}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 4}, ImpactedDependencyName: "component-B", - Components: []formats.ComponentRow{{Name: "component-B", Location: &formats.Location{File: "target"}}}, + // Direct + Components: []formats.ComponentRow{{ + Name: "component-B", + Location: &formats.Location{File: "target"}, + }}, }, - Applicable: jasutils.NotApplicable.String(), - Cves: []formats.CveRow{{Id: "CVE-1"}}, + ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-B"}}}, }, { - Summary: "summary-2", - IssueId: "XRAY-2", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low"}, - ImpactedDependencyName: "component-B", - Components: []formats.ComponentRow{{Name: "component-B", Location: &formats.Location{File: "target"}}}, - }, - Applicable: jasutils.Applicability.String(), + Summary: "summary-2", + IssueId: "XRAY-2", + Applicable: jasutils.Applicable.String(), Cves: []formats.CveRow{{ Id: "CVE-2", Applicability: &formats.Applicability{ - Status: jasutils.Applicability.String(), - Evidence: []formats.Evidence{formats.Evidence{ - Location: formats.Location{File: "target/file", StartLine: 0, StartColumn: 0, EndLine: 0, EndColumn: 0, Snippet: "snippet"}, + Status: jasutils.Applicable.String(), + Evidence: []formats.Evidence{{ + Location: formats.Location{File: "file", StartLine: 0, StartColumn: 0, EndLine: 0, EndColumn: 0, Snippet: "snippet"}, + Reason: "applic_CVE-2", }}, }, }}, - }, - }, - }, - { - name: "Vulnerabilities only - with allowed licenses", - input: testScaScanResults, - target: "target", - entitledForJas: false, - pretty: false, - applicablityRuns: []*sarif.Run{}, - expectedOutput: []formats.VulnerabilityOrViolationRow{ - { - Summary: "summary-1", - IssueId: "XRAY-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "high"}, - ImpactedDependencyName: "component-A", - }, - }, - { - Summary: "summary-1", - IssueId: "XRAY-1", ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "high"}, - ImpactedDependencyName: "component-B", - }, - }, - { - Summary: "summary-2", - IssueId: "XRAY-2", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "low"}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 11}, ImpactedDependencyName: "component-B", + // Direct + Components: []formats.ComponentRow{{ + Name: "component-B", + Location: &formats.Location{File: "target"}, + }}, }, + ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-B"}}}, }, }, }, @@ -336,7 +406,7 @@ func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - out, err := PrepareSimpleJsonVulnerabilities(tc.target, tc.input, tc.pretty, tc.entitledForJas, tc.applicablityRuns...) + out, err := PrepareSimpleJsonVulnerabilities(tc.target, tc.input, false, tc.entitledForJas, tc.applicablityRuns...) assert.NoError(t, err) assert.ElementsMatch(t, tc.expectedOutput, out) }) @@ -349,44 +419,19 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { input []services.Violation target string entitledForJas bool - pretty bool applicablityRuns []*sarif.Run expectedSecurityOutput []formats.VulnerabilityOrViolationRow expectedLicenseOutput []formats.LicenseRow expectedOperationalRiskOutput []formats.OperationalRiskViolationRow }{ { - name: "No violations", - input: []services.Violation{}, - target: "target", - entitledForJas: false, - pretty: false, - applicablityRuns: []*sarif.Run{}, - expectedSecurityOutput: []formats.VulnerabilityOrViolationRow{}, + name: "No violations", + target: "target", }, { - name: "Violations with no applicability", - input: []services.Violation{ - { - IssueId: "XRAY-1", - Summary: "summary-1", - Severity: "High", - ViolationType: "security", - Components: map[string]services.Component{"component-A": {}, "component-B": {}}, - }, - { - IssueId: "XRAY-2", - Summary: "summary-2", - Severity: "Low", - ViolationType: "license", - LicenseKey: "license-1", - Components: map[string]services.Component{"component-B": {}}, - }, - }, - target: "target", - entitledForJas: false, - pretty: false, - applicablityRuns: []*sarif.Run{}, + name: "Violations not entitled for JAS", + input: testScaScanViolation, + target: "target", expectedSecurityOutput: []formats.VulnerabilityOrViolationRow{ { Summary: "summary-1", @@ -437,7 +482,6 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { }, target: "target", entitledForJas: true, - pretty: false, applicablityRuns: []*sarif.Run{ sarifutils.CreateRunWithDummyResults( sarifutils.CreateDummyPassingResult("applic_CVE-1"), @@ -475,7 +519,7 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { ImpactedDependencyName: "component-B", Components: []formats.ComponentRow{{Name: "component-B", Location: &formats.Location{File: "target"}}}, }, - Applicable: jasutils.Applicability.String(), + Applicable: jasutils.Applicable.String(), }, }, }, @@ -486,7 +530,7 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - securityOutput, licenseOutput, operationalRiskOutput, err := PrepareSimpleJsonViolations(tc.target, tc.input, tc.pretty, tc.entitledForJas, tc.applicablityRuns...) + securityOutput, licenseOutput, operationalRiskOutput, err := PrepareSimpleJsonViolations(tc.target, tc.input, false, tc.entitledForJas, tc.applicablityRuns...) assert.NoError(t, err) assert.ElementsMatch(t, tc.expectedSecurityOutput, securityOutput) assert.ElementsMatch(t, tc.expectedLicenseOutput, licenseOutput) diff --git a/utils/results/output/securityJobSummary_test.go b/utils/results/output/securityJobSummary_test.go index 1fb027e5..df8609a3 100644 --- a/utils/results/output/securityJobSummary_test.go +++ b/utils/results/output/securityJobSummary_test.go @@ -11,7 +11,7 @@ import ( ) var ( - summaryExpectedContentDir = filepath.Join("..", "tests", "testdata", "other", "jobSummary") + summaryExpectedContentDir = filepath.Join("..", "..", "..", "tests", "testdata", "other", "output", "jobSummary") ) func TestConvertSummaryToString(t *testing.T) { diff --git a/utils/results/results.go b/utils/results/results.go index f06916e0..122b2c4c 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -46,6 +46,7 @@ type TargetResults struct { } type ScaScanResults struct { + ScanTarget IsMultipleRootProject *bool `json:"is_multiple_root_project,omitempty"` // Target of the scan Descriptors []string `json:"descriptors,omitempty"` diff --git a/utils/severityutils/severity.go b/utils/severityutils/severity.go index dab73675..99955f79 100644 --- a/utils/severityutils/severity.go +++ b/utils/severityutils/severity.go @@ -203,14 +203,6 @@ func ParseForDetails(severity string, sarifSeverity bool, applicabilityStatus ja return } -func ParseToSeverityDetails(severity string, sarifSeverity, pretty bool, applicabilityStatus jasutils.ApplicabilityStatus) (out formats.SeverityDetails, err error) { - parsed, err := ParseSeverity(severity, sarifSeverity) - if err != nil { - return - } - return GetSeverityDetails(parsed, applicabilityStatus).ToDetails(parsed, pretty), nil -} - // -- Getters functions (With default values) -- func GetAsDetails(severity Severity, applicabilityStatus jasutils.ApplicabilityStatus, pretty bool) formats.SeverityDetails { @@ -218,6 +210,9 @@ func GetAsDetails(severity Severity, applicabilityStatus jasutils.ApplicabilityS } func GetSeverityDetails(severity Severity, applicabilityStatus jasutils.ApplicabilityStatus) *SeverityDetails { + if applicabilityStatus == jasutils.NotScanned { + applicabilityStatus = jasutils.Applicable + } details, err := ParseForDetails(severity.String(), false, applicabilityStatus) if err != nil { return &SeverityDetails{Priority: 0, Score: 0} diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index ac7e2a05..5df5136a 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -2,6 +2,7 @@ package validations import ( "encoding/json" + "fmt" "strings" "testing" @@ -26,12 +27,12 @@ func ValidateCommandSarifOutput(t *testing.T, params ValidationParams) { results, ok := params.Actual.(*sarif.Report) if assert.True(t, ok) { ValidateSarifIssuesCount(t, params, results) - // if params.Expected != nil { - // expectedResults, ok := params.Expected.(sarif.Report) - // if assert.True(t, ok) { - // ValidateScanResponses(t, params.ExactResultsMatch, expectedResults, results) - // } - // } + if params.Expected != nil { + expectedResults, ok := params.Expected.(*sarif.Report) + if assert.True(t, ok) { + ValidateSarifResults(t, params.ExactResultsMatch, expectedResults, results) + } + } } } @@ -110,3 +111,118 @@ func isSecurityIssue(result *sarif.Result) bool { } return false } + +func ValidateSarifResults(t *testing.T, exactMatch bool, expected, actual *sarif.Report) { + validateContent(t, exactMatch, StringValidation{Expected: expected.Version, Actual: actual.Version, Msg: "Sarif version mismatch"}) + for _, run := range expected.Runs { + // expect Invocation + if !assert.Len(t, run.Invocations, 1, "Expected exactly one invocation for run with tool name %s", run.Tool.Driver.Name) { + continue + } + actualRun := getRunByInvocationTargetAndToolName(sarifutils.GetInvocationWorkingDirectory(run.Invocations[0]), run.Tool.Driver.Name, actual.Runs) + if !assert.NotNil(t, actualRun, "Expected run with tool name %s and working directory %s not found", run.Tool.Driver.Name, sarifutils.GetInvocationWorkingDirectory(run.Invocations[0])) { + continue + } + validateSarifRun(t, exactMatch, run, actualRun) + } +} + +func getRunByInvocationTargetAndToolName(target, toolName string, content []*sarif.Run) *sarif.Run { + potentialRuns := sarifutils.GetRunsByWorkingDirectory(target, content...) + for _, run := range potentialRuns { + if run.Tool.Driver != nil && run.Tool.Driver.Name == toolName { + return run + } + } + return nil +} + +func validateSarifRun(t *testing.T, exactMatch bool, expected, actual *sarif.Run) { + validateContent(t, exactMatch, + PointerValidation[string]{Expected: expected.Tool.Driver.InformationURI, Actual: actual.Tool.Driver.InformationURI, Msg: fmt.Sprintf("Run tool information URI mismatch for tool %s", expected.Tool.Driver.Name)}, + PointerValidation[string]{Expected: expected.Tool.Driver.Version, Actual: actual.Tool.Driver.Version, Msg: fmt.Sprintf("Run tool version mismatch for tool %s", expected.Tool.Driver.Name)}, + ) + // validate rules + for _, expectedRule := range expected.Tool.Driver.Rules { + rule, err := actual.GetRuleById(expectedRule.ID) + if !(assert.NoError(t, err, fmt.Sprintf("Run tool %s: Expected rule with ID %s not found", expected.Tool.Driver.Name, expectedRule.ID)) || + assert.NotNil(t, rule, fmt.Sprintf("Run tool %s: Expected rule with ID %s not found", expected.Tool.Driver.Name, expectedRule.ID))) { + continue + } + validateSarifRule(t, exactMatch, expected.Tool.Driver.Name, expectedRule, rule) + } + // validate results + for _, expectedResult := range expected.Results { + result := getResultByResultId(expectedResult, actual.Results) + if !assert.NotNil(t, result, fmt.Sprintf("Run tool %s: Expected result with rule ID %s not found", expected.Tool.Driver.Name, *expectedResult.RuleID)) { + continue + } + validateSarifResult(t, exactMatch, expected.Tool.Driver.Name, expectedResult, result) + } +} + +func validateSarifRule(t *testing.T, exactMatch bool, toolName string, expected, actual *sarif.ReportingDescriptor) { + validateContent(t, exactMatch, + StringValidation{Expected: sarifutils.GetRuleFullDescription(expected), Actual: sarifutils.GetRuleFullDescription(actual), Msg: fmt.Sprintf("Run tool %s: Rule full description mismatch for rule %s", toolName, expected.ID)}, + StringValidation{Expected: sarifutils.GetRuleFullDescriptionMarkdown(expected), Actual: sarifutils.GetRuleFullDescriptionMarkdown(actual), Msg: fmt.Sprintf("Run tool %s: Rule full description markdown mismatch for rule %s", toolName, expected.ID)}, + StringValidation{Expected: sarifutils.GetRuleShortDescription(expected), Actual: sarifutils.GetRuleShortDescription(actual), Msg: fmt.Sprintf("Run tool %s: Rule short description mismatch for rule %s", toolName, expected.ID)}, + StringValidation{Expected: sarifutils.GetRuleHelp(expected), Actual: sarifutils.GetRuleHelp(actual), Msg: fmt.Sprintf("Run tool %s: Rule help mismatch for rule %s", toolName, expected.ID)}, + StringValidation{Expected: sarifutils.GetRuleHelpMarkdown(expected), Actual: sarifutils.GetRuleHelpMarkdown(actual), Msg: fmt.Sprintf("Run tool %s: Rule help markdown mismatch for rule %s", toolName, expected.ID)}, + ) + // validate properties + validateSarifProperties(t, exactMatch, expected.Properties, actual.Properties, toolName, expected.ID) +} + +func getResultByResultId(expected *sarif.Result, actual []*sarif.Result) *sarif.Result { + for _, result := range actual { + // TODO: Need to be improved to handle secrets results (have one result for each location with same info, so need to compare the locations) + if result.RuleID == expected.RuleID && + len(result.Locations) == len(expected.Locations) && + sarifutils.GetResultMsgText(result) == sarifutils.GetResultMsgText(expected) { + return result + } + } + return nil +} + +func validateSarifResult(t *testing.T, exactMatch bool, toolName string, expected, actual *sarif.Result) { + validateContent(t, exactMatch, + StringValidation{Expected: sarifutils.GetResultLevel(expected), Actual: sarifutils.GetResultLevel(actual), Msg: fmt.Sprintf("Run tool %s: Result level mismatch for rule %s", toolName, *expected.RuleID)}, + ) + // validate properties + validateSarifProperties(t, exactMatch, expected.Properties, actual.Properties, toolName, *expected.RuleID) + // validate locations + for _, expectedLocation := range expected.Locations { + location := getLocationById(expectedLocation, actual.Locations) + if !assert.NotNil(t, location, "Expected location with physical location %s not found", expectedLocation.PhysicalLocation) { + continue + } + } +} + +func getLocationById(expected *sarif.Location, actual []*sarif.Location) *sarif.Location { + for _, location := range actual { + if sarifutils.GetLocationId(location) == sarifutils.GetLocationId(expected) { + return location + } + } + return nil +} + +func validateSarifProperties(t *testing.T, exactMatch bool, expected, actual map[string]interface{}, toolName, ruleID string) { + for key, expectedValue := range expected { + actualValue, ok := actual[key] + if !assert.True(t, ok, fmt.Sprintf("Run tool %s: Expected property with key %s not found for rule %s", toolName, key, ruleID)) { + continue + } + // If the property is a string, compare the string values + if expectedStr, ok := expectedValue.(string); ok { + actualStr, ok := actualValue.(string) + if assert.True(t, ok, fmt.Sprintf("Run tool %s: Expected property with key %s is not a string for rule %s", toolName, key, ruleID)) { + validateContent(t, exactMatch, StringValidation{Expected: expectedStr, Actual: actualStr, Msg: fmt.Sprintf("Run tool %s: Rule property mismatch for rule %s", toolName, ruleID)}) + continue + } + assert.Fail(t, fmt.Sprintf("Run tool %s: Expected property with key %s is a string for rule %s", toolName, key, ruleID)) + } + } +} diff --git a/utils/validations/test_validate_simple_json.go b/utils/validations/test_validate_simple_json.go index fdb2e1b2..d5a3bf38 100644 --- a/utils/validations/test_validate_simple_json.go +++ b/utils/validations/test_validate_simple_json.go @@ -82,8 +82,8 @@ func ValidateSimpleJsonIssuesCount(t *testing.T, params ValidationParams, result } func ValidateSimpleJsonResults(t *testing.T, exactMatch bool, expected, actual formats.SimpleJsonResults) { - validatePairs(t, exactMatch, ValidationPair{Expected: expected.MultiScanId, Actual: actual.MultiScanId, ErrMsg: "MultiScanId mismatch"}) - validatePairs(t, false, ValidationPair{Expected: len(expected.Errors), Actual: len(actual.Errors), ErrMsg: "Errors count mismatch"}) + validateContent(t, exactMatch, StringValidation{Expected: expected.MultiScanId, Actual: actual.MultiScanId, Msg: "MultiScanId mismatch"}) + validateContent(t, false, NumberValidation[int]{Expected: len(expected.Errors), Actual: len(actual.Errors), Msg: "Errors count mismatch"}) // Validate vulnerabilities for _, expectedVulnerability := range expected.Vulnerabilities { vulnerability := getVulnerabilityOrViolationByIssueId(expectedVulnerability.IssueId, actual.Vulnerabilities) @@ -112,25 +112,25 @@ func getVulnerabilityOrViolationByIssueId(issueId string, content []formats.Vuln } func validateVulnerabilityOrViolationRow(t *testing.T, exactMatch bool, expected, actual formats.VulnerabilityOrViolationRow) { - validatePairs(t, exactMatch, - ValidationPair{Expected: expected.Summary, Actual: actual.Summary, ErrMsg: fmt.Sprintf("IssueId %s: Summary mismatch", expected.IssueId)}, - ValidationPair{Expected: expected.Severity, Actual: actual.Severity, ErrMsg: fmt.Sprintf("IssueId %s: Severity mismatch", expected.IssueId)}, - ValidationPair{Expected: expected.Applicable, Actual: actual.Applicable, ErrMsg: fmt.Sprintf("IssueId %s: Applicable mismatch", expected.IssueId)}, - ValidationPair{Expected: expected.Technology, Actual: actual.Technology, ErrMsg: fmt.Sprintf("IssueId %s: Technology mismatch", expected.IssueId)}, - ValidationPair{Expected: expected.References, Actual: actual.References, ErrMsg: fmt.Sprintf("IssueId %s: References mismatch", expected.IssueId)}, - - ValidationPair{Expected: expected.ImpactedDependencyName, Actual: actual.ImpactedDependencyName, ErrMsg: fmt.Sprintf("IssueId %s: ImpactedDependencyName mismatch", expected.IssueId)}, - ValidationPair{Expected: expected.ImpactedDependencyVersion, Actual: actual.ImpactedDependencyVersion, ErrMsg: fmt.Sprintf("IssueId %s: ImpactedDependencyVersion mismatch", expected.IssueId)}, - ValidationPair{Expected: expected.ImpactedDependencyType, Actual: actual.ImpactedDependencyType, ErrMsg: fmt.Sprintf("IssueId %s: ImpactedDependencyType mismatch", expected.IssueId)}, - - ValidationPair{Expected: expected.FixedVersions, Actual: actual.FixedVersions, ErrMsg: fmt.Sprintf("IssueId %s: FixedVersions mismatch", expected.IssueId)}, + validateContent(t, exactMatch, + StringValidation{Expected: expected.Summary, Actual: actual.Summary, Msg: fmt.Sprintf("IssueId %s: Summary mismatch", expected.IssueId)}, + StringValidation{Expected: expected.Severity, Actual: actual.Severity, Msg: fmt.Sprintf("IssueId %s: Severity mismatch", expected.IssueId)}, + StringValidation{Expected: expected.Applicable, Actual: actual.Applicable, Msg: fmt.Sprintf("IssueId %s: Applicable mismatch", expected.IssueId)}, + StringValidation{Expected: expected.Technology.String(), Actual: actual.Technology.String(), Msg: fmt.Sprintf("IssueId %s: Technology mismatch", expected.IssueId)}, + ListValidation[string]{Expected: expected.References, Actual: actual.References, Msg: fmt.Sprintf("IssueId %s: References mismatch", expected.IssueId)}, + + StringValidation{Expected: expected.ImpactedDependencyName, Actual: actual.ImpactedDependencyName, Msg: fmt.Sprintf("IssueId %s: ImpactedDependencyName mismatch", expected.IssueId)}, + StringValidation{Expected: expected.ImpactedDependencyVersion, Actual: actual.ImpactedDependencyVersion, Msg: fmt.Sprintf("IssueId %s: ImpactedDependencyVersion mismatch", expected.IssueId)}, + StringValidation{Expected: expected.ImpactedDependencyType, Actual: actual.ImpactedDependencyType, Msg: fmt.Sprintf("IssueId %s: ImpactedDependencyType mismatch", expected.IssueId)}, + + ListValidation[string]{Expected: expected.FixedVersions, Actual: actual.FixedVersions, Msg: fmt.Sprintf("IssueId %s: FixedVersions mismatch", expected.IssueId)}, ) - if validatePairs(t, exactMatch, ValidationPair{Expected: expected.JfrogResearchInformation, Actual: actual.JfrogResearchInformation}) && expected.JfrogResearchInformation != nil { - validatePairs(t, exactMatch, - ValidationPair{Expected: expected.JfrogResearchInformation.Summary, Actual: actual.JfrogResearchInformation.Summary, ErrMsg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Summary mismatch", expected.IssueId)}, - ValidationPair{Expected: expected.JfrogResearchInformation.Severity, Actual: actual.JfrogResearchInformation.Severity, ErrMsg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Severity mismatch", expected.IssueId)}, - ValidationPair{Expected: expected.JfrogResearchInformation.Remediation, Actual: actual.JfrogResearchInformation.Remediation, ErrMsg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Remediation mismatch", expected.IssueId)}, - ValidationPair{Expected: expected.JfrogResearchInformation.SeverityReasons, Actual: actual.JfrogResearchInformation.SeverityReasons, ErrMsg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.SeverityReasons mismatch", expected.IssueId)}, + if ValidatePointersAndNotNil(t, exactMatch, PointerValidation[formats.JfrogResearchInformation]{Expected: expected.JfrogResearchInformation, Actual: actual.JfrogResearchInformation, Msg: fmt.Sprintf("IssueId %s: JfrogResearchInformation mismatch", expected.IssueId)}) { + validateContent(t, exactMatch, + StringValidation{Expected: expected.JfrogResearchInformation.Summary, Actual: actual.JfrogResearchInformation.Summary, Msg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Summary mismatch", expected.IssueId)}, + StringValidation{Expected: expected.JfrogResearchInformation.Severity, Actual: actual.JfrogResearchInformation.Severity, Msg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Severity mismatch", expected.IssueId)}, + StringValidation{Expected: expected.JfrogResearchInformation.Remediation, Actual: actual.JfrogResearchInformation.Remediation, Msg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Remediation mismatch", expected.IssueId)}, + ListValidation[formats.JfrogResearchSeverityReason]{Expected: expected.JfrogResearchInformation.SeverityReasons, Actual: actual.JfrogResearchInformation.SeverityReasons, Msg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.SeverityReasons mismatch", expected.IssueId)}, ) } validateComponentRows(t, expected.IssueId, exactMatch, expected.Components, actual.Components) @@ -156,11 +156,11 @@ func validateComponentRows(t *testing.T, issueId string, exactMatch bool, expect } func validateComponentRow(t *testing.T, issueId string, exactMatch bool, expected, actual formats.ComponentRow) { - validatePairs(t, exactMatch, - ValidationPair{Expected: expected.Location, Actual: actual.Location, ErrMsg: fmt.Sprintf("IssueId %s: Component %s:%s Location mismatch", issueId, expected.Name, expected.Version)}, + validateContent(t, exactMatch, + PointerValidation[formats.Location]{Expected: expected.Location, Actual: actual.Location, Msg: fmt.Sprintf("IssueId %s: Component %s:%s Location mismatch", issueId, expected.Name, expected.Version)}, ) if expected.Location != nil { - validatePairs(t, exactMatch, ValidationPair{Expected: expected.Location.File, Actual: actual.Location.File, ErrMsg: fmt.Sprintf("IssueId %s: Component %s:%s Location.File mismatch", issueId, expected.Name, expected.Version)}) + validateContent(t, exactMatch, StringValidation{Expected: expected.Location.File, Actual: actual.Location.File, Msg: fmt.Sprintf("IssueId %s: Component %s:%s Location.File mismatch", issueId, expected.Name, expected.Version)}) } } @@ -187,15 +187,15 @@ func validateCveRows(t *testing.T, issueId string, exactMatch bool, expected, ac } func validateCveRow(t *testing.T, issueId string, exactMatch bool, expected, actual formats.CveRow) { - validatePairs(t, exactMatch, - ValidationPair{Expected: expected.CvssV2, Actual: actual.CvssV2, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: CvssV2 mismatch", issueId, expected.Id)}, - ValidationPair{Expected: expected.CvssV3, Actual: actual.CvssV3, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: CvssV3 mismatch", issueId, expected.Id)}, + validateContent(t, exactMatch, + StringValidation{Expected: expected.CvssV2, Actual: actual.CvssV2, Msg: fmt.Sprintf("IssueId %s: Cve %s: CvssV2 mismatch", issueId, expected.Id)}, + StringValidation{Expected: expected.CvssV3, Actual: actual.CvssV3, Msg: fmt.Sprintf("IssueId %s: Cve %s: CvssV3 mismatch", issueId, expected.Id)}, ) - if validatePairs(t, exactMatch, ValidationPair{Expected: expected.Applicability, Actual: actual.Applicability, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: Applicability mismatch", issueId, expected.Id)}) && expected.Applicability != nil { - validatePairs(t, exactMatch, - ValidationPair{Expected: expected.Applicability.Status, Actual: actual.Applicability.Status, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.Status mismatch", issueId, expected.Id)}, - ValidationPair{Expected: expected.Applicability.ScannerDescription, Actual: actual.Applicability.ScannerDescription, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.ScannerDescription mismatch", issueId, expected.Id)}, - ValidationPair{Expected: expected.Applicability.Evidence, Actual: actual.Applicability.Evidence, ErrMsg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.Evidence mismatch", issueId, expected.Id)}, + if ValidatePointersAndNotNil(t, exactMatch, PointerValidation[formats.Applicability]{Expected: expected.Applicability, Actual: actual.Applicability, Msg: fmt.Sprintf("IssueId %s: Cve %s: Applicability mismatch", issueId, expected.Id)}) { + validateContent(t, exactMatch, + StringValidation{Expected: expected.Applicability.Status, Actual: actual.Applicability.Status, Msg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.Status mismatch", issueId, expected.Id)}, + StringValidation{Expected: expected.Applicability.ScannerDescription, Actual: actual.Applicability.ScannerDescription, Msg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.ScannerDescription mismatch", issueId, expected.Id)}, + ListValidation[formats.Evidence]{Expected: expected.Applicability.Evidence, Actual: actual.Applicability.Evidence, Msg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.Evidence mismatch", issueId, expected.Id)}, ) } } diff --git a/utils/validations/test_validation.go b/utils/validations/test_validation.go index 755cb372..1c59ddee 100644 --- a/utils/validations/test_validation.go +++ b/utils/validations/test_validation.go @@ -32,57 +32,79 @@ type ValidationParams struct { Secrets int } -type ValidationPair struct { - Expected interface{} - Actual interface{} - ErrMsg string +// type ValidationPair struct { +// Expected interface{} +// Actual interface{} +// ErrMsg string +// } + +type Validation interface { + Validate(t *testing.T, exactMatch bool) bool + ErrMsgs(t *testing.T) []string } -func (vp ValidationPair) ErrMsgs(t *testing.T) []string { - expectedStr := fmt.Sprintf("%v", vp.Expected) - var err error - // If the expected value is a struct, convert it to a JSON string. - if _, ok := vp.Expected.(string); !ok { - expectedStr, err = utils.GetAsJsonString(vp.Expected) - assert.NoError(t, err) +type StringValidation struct { + Expected string + Actual string + Msg string +} + +func (sv StringValidation) Validate(t *testing.T, exactMatch bool) bool { + return validateStrContent(t, sv.Expected, sv.Actual, exactMatch, sv.ErrMsgs(t)) +} + +func validateStrContent(t *testing.T, expected, actual string, actualValue bool, msgAndArgs ...interface{}) bool { + if actualValue { + return assert.Equal(t, expected, actual, msgAndArgs...) } - actualStr := fmt.Sprintf("%v", vp.Actual) - // If the actual value is a struct, convert it to a JSON string. - if _, ok := vp.Actual.(string); !ok { - actualStr, err = utils.GetAsJsonString(vp.Actual) - assert.NoError(t, err) + if expected != "" { + return assert.NotEmpty(t, actual, msgAndArgs...) + } else { + return assert.Empty(t, actual, msgAndArgs...) } - return []string{vp.ErrMsg, fmt.Sprintf("\n* Expected:\n%s\n\n* Actual:\n%s\n", expectedStr, actualStr)} } -func validatePairs(t *testing.T, exactMatch bool, pairs ...ValidationPair) bool { - for _, pair := range pairs { - switch expected := pair.Expected.(type) { - case string: - actual, ok := pair.Actual.(string) - if !ok { - return assert.Fail(t, "Expected a string value, but got a different type.", pair.ErrMsgs(t)) - } - if !validateStrContent(t, expected, actual, exactMatch, pair.ErrMsgs(t)) { - return false - } - case *interface{}: - if !validatePointers(t, expected, pair.Actual, exactMatch, pair.ErrMsgs(t)) { - return false - } - case []interface{}: - if exactMatch { - if !assert.ElementsMatch(t, expected, pair.Actual, pair.ErrMsgs(t)) { - return false - } - } else if !assert.Subset(t, expected, pair.Actual, pair.ErrMsgs(t)) { - return false - } - default: - return assert.Equal(t, expected, pair.Actual, pair.ErrMsgs(t)) - } +func (sv StringValidation) ErrMsgs(_ *testing.T) []string { + return errMsg(sv.Expected, sv.Actual, sv.Msg) +} + +type NumberValidation[T any] struct { + Expected T + Actual T + Msg string +} + +func (nvp NumberValidation[T]) Validate(t *testing.T, exactMatch bool) bool { + return validateNumberContent(t, nvp.Expected, nvp.Actual, exactMatch, nvp.ErrMsgs(t)) +} + +func validateNumberContent(t *testing.T, expected, actual interface{}, actualValue bool, msgAndArgs ...interface{}) bool { + if actualValue { + return assert.Equal(t, expected, actual, msgAndArgs...) } - return true + if expected != 0 { + return assert.NotZero(t, actual, msgAndArgs...) + } else { + return assert.Zero(t, actual, msgAndArgs...) + } +} + +func (nvp NumberValidation[T]) ErrMsgs(_ *testing.T) []string { + return errMsg(fmt.Sprintf("%v", nvp.Expected), fmt.Sprintf("%v", nvp.Actual), nvp.Msg) +} + +type PointerValidation[T any] struct { + Expected *T + Actual *T + Msg string +} + +func (pvp PointerValidation[T]) Validate(t *testing.T, exactMatch bool) bool { + return validatePointers(t, pvp.Expected, pvp.Actual, exactMatch, pvp.ErrMsgs(t)) +} + +func ValidatePointersAndNotNil[T any](t *testing.T, exactMatch bool, pair PointerValidation[T]) bool { + return validatePointers(t, pair.Expected, pair.Actual, exactMatch, pair.Msg) && pair.Expected != nil } func validatePointers(t *testing.T, expected, actual interface{}, actualValue bool, msgAndArgs ...interface{}) bool { @@ -95,13 +117,105 @@ func validatePointers(t *testing.T, expected, actual interface{}, actualValue bo return assert.Nil(t, actual, msgAndArgs...) } -func validateStrContent(t *testing.T, expected, actual string, actualValue bool, msgAndArgs ...interface{}) bool { - if actualValue { - return assert.Equal(t, expected, actual, msgAndArgs...) +func (pvp PointerValidation[T]) ErrMsgs(t *testing.T) []string { + return jsonErrMsg(t, pvp.Expected, pvp.Actual, pvp.Msg) +} + +type ListValidation[T any] struct { + Expected []T + Actual []T + Msg string +} + +func (lvp ListValidation[T]) Validate(t *testing.T, exactMatch bool) bool { + return validateLists(t, lvp.Expected, lvp.Actual, exactMatch, lvp.ErrMsgs(t)) +} + +func validateLists(t *testing.T, expected, actual interface{}, exactMatch bool, msgAndArgs ...interface{}) bool { + if exactMatch { + return assert.ElementsMatch(t, expected, actual, msgAndArgs...) } - if expected != "" { - return assert.NotEmpty(t, actual, msgAndArgs...) - } else { - return assert.Empty(t, actual, msgAndArgs...) + return assert.Subset(t, actual, expected, msgAndArgs...) +} + +func (lvp ListValidation[T]) ErrMsgs(t *testing.T) []string { + return jsonErrMsg(t, lvp.Expected, lvp.Actual, lvp.Msg) +} + +func jsonErrMsg(t *testing.T, expected, actual any, msg string) []string { + var expectedStr, actualStr string + var err error + if expected != nil { + expectedStr, err = utils.GetAsJsonString(expected) + assert.NoError(t, err) } + if actual != nil { + actualStr, err = utils.GetAsJsonString(actual) + assert.NoError(t, err) + } + return errMsg(expectedStr, actualStr, msg) +} + +func errMsg(expected, actual string, msg string) []string { + return []string{msg, fmt.Sprintf("\n* Expected:\n'%s'\n\n* Actual:\n%s\n", expected, actual)} +} + +// func (vp ValidationPair) ErrMsgs(t *testing.T) []string { +// expectedStr := fmt.Sprintf("%v", vp.Expected) +// var err error +// // If the expected value is a struct, convert it to a JSON string. +// if _, ok := vp.Expected.(string); !ok { +// expectedStr, err = utils.GetAsJsonString(vp.Expected) +// assert.NoError(t, err) +// } +// actualStr := fmt.Sprintf("%v", vp.Actual) +// // If the actual value is a struct, convert it to a JSON string. +// if _, ok := vp.Actual.(string); !ok { +// actualStr, err = utils.GetAsJsonString(vp.Actual) +// assert.NoError(t, err) +// } +// return []string{vp.ErrMsg, fmt.Sprintf("\n* Expected:\n%s\n\n* Actual:\n%s\n", expectedStr, actualStr)} +// } + +// func validatePairAndNotNil(t *testing.T, exactMatch bool, pair ValidationPair) bool { +// validated := validatePairs(t, exactMatch, pair) +// return validated && pair.Expected != nil +// } + +func validateContent(t *testing.T, exactMatch bool, pairs ...Validation) bool { + for _, pair := range pairs { + if !pair.Validate(t, exactMatch) { + return false + } + } + return true + + // for _, pair := range pairs { + // // Problem, should have reflecT!!!!! Use template instead! + // switch expected := pair.Expected.(type) { + // case string: + // actual, ok := pair.Actual.(string) + // if !ok { + // return assert.Fail(t, "Expected a string value, but got a different type.", pair.ErrMsgs(t)) + // } + // if !validateStrContent(t, expected, actual, exactMatch, pair.ErrMsgs(t)) { + // return false + // } + // case *interface{}: + // if !validatePointers(t, expected, pair.Actual, exactMatch, pair.ErrMsgs(t)) { + // return false + // } + // case []interface{}: + // if exactMatch { + // if !assert.ElementsMatch(t, expected, pair.Actual, pair.ErrMsgs(t)) { + // return false + // } + // } else if !assert.Subset(t, expected, pair.Actual, pair.ErrMsgs(t)) { + // return false + // } + // default: + // return assert.Equal(t, expected, pair.Actual, pair.ErrMsgs(t)) + // } + // } + // return true } From 4be27f03aac5140076829807abc74537636c3aee Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 21 Jul 2024 14:10:26 +0300 Subject: [PATCH 29/82] fix tests --- commands/audit/audit_test.go | 10 + commands/enrich/enrich.go | 27 +- jas/common.go | 2 +- jas/sast/sastscanner.go | 9 +- .../other/output/formats/audit_results.json | 16 +- .../other/output/formats/audit_sarif.json | 398 +++++++++--------- utils/formats/sarifutils/sarifutils.go | 7 + utils/results/common.go | 7 +- .../conversion/sarifparser/sarifparser.go | 1 + utils/results/results.go | 13 +- utils/validations/test_validate_sarif.go | 28 +- .../validations/test_validate_simple_json.go | 6 +- utils/validations/test_validation.go | 4 +- 13 files changed, 272 insertions(+), 256 deletions(-) diff --git a/commands/audit/audit_test.go b/commands/audit/audit_test.go index 542eaa8f..1bb2a8ba 100644 --- a/commands/audit/audit_test.go +++ b/commands/audit/audit_test.go @@ -34,6 +34,7 @@ func TestDetectScansToPreform(t *testing.T) { Technology: techutils.Maven, Target: filepath.Join(dir, "dir", "maven"), }, + JasResults: &results.JasScansResults{}, ScaResults: &results.ScaScanResults{ Descriptors: []string{ filepath.Join(dir, "dir", "maven", "pom.xml"), @@ -47,6 +48,7 @@ func TestDetectScansToPreform(t *testing.T) { Technology: techutils.Npm, Target: filepath.Join(dir, "dir", "npm"), }, + JasResults: &results.JasScansResults{}, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "dir", "npm", "package.json")}, }, @@ -56,6 +58,7 @@ func TestDetectScansToPreform(t *testing.T) { Technology: techutils.Go, Target: filepath.Join(dir, "dir", "go"), }, + JasResults: &results.JasScansResults{}, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "dir", "go", "go.mod")}, }, @@ -76,6 +79,7 @@ func TestDetectScansToPreform(t *testing.T) { Technology: techutils.Maven, Target: filepath.Join(dir, "dir", "maven"), }, + JasResults: &results.JasScansResults{}, ScaResults: &results.ScaScanResults{ Descriptors: []string{ filepath.Join(dir, "dir", "maven", "pom.xml"), @@ -89,6 +93,7 @@ func TestDetectScansToPreform(t *testing.T) { Technology: techutils.Npm, Target: filepath.Join(dir, "dir", "npm"), }, + JasResults: &results.JasScansResults{}, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "dir", "npm", "package.json")}, }, @@ -98,6 +103,7 @@ func TestDetectScansToPreform(t *testing.T) { Technology: techutils.Go, Target: filepath.Join(dir, "dir", "go"), }, + JasResults: &results.JasScansResults{}, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "dir", "go", "go.mod")}, }, @@ -107,6 +113,7 @@ func TestDetectScansToPreform(t *testing.T) { Technology: techutils.Yarn, Target: filepath.Join(dir, "yarn"), }, + JasResults: &results.JasScansResults{}, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "yarn", "package.json")}, }, @@ -116,6 +123,7 @@ func TestDetectScansToPreform(t *testing.T) { Technology: techutils.Pip, Target: filepath.Join(dir, "yarn", "Pip"), }, + JasResults: &results.JasScansResults{}, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "yarn", "Pip", "requirements.txt")}, }, @@ -125,6 +133,7 @@ func TestDetectScansToPreform(t *testing.T) { Technology: techutils.Pipenv, Target: filepath.Join(dir, "yarn", "Pipenv"), }, + JasResults: &results.JasScansResults{}, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "yarn", "Pipenv", "Pipfile")}, }, @@ -134,6 +143,7 @@ func TestDetectScansToPreform(t *testing.T) { Technology: techutils.Nuget, Target: filepath.Join(dir, "Nuget"), }, + JasResults: &results.JasScansResults{}, ScaResults: &results.ScaScanResults{ Descriptors: []string{filepath.Join(dir, "Nuget", "project.sln"), filepath.Join(dir, "Nuget", "Nuget-sub", "project.csproj")}, }, diff --git a/commands/enrich/enrich.go b/commands/enrich/enrich.go index d0606c46..b7aacd95 100644 --- a/commands/enrich/enrich.go +++ b/commands/enrich/enrich.go @@ -156,21 +156,14 @@ func (enrichCmd *EnrichCommand) Run() (err error) { log.Info("JFrog Xray version is:", xrayVersion) - threads := 1 - if enrichCmd.threads > 1 { - threads = enrichCmd.threads - } - scanResults := results.NewCommandResults(xrayVersion, false) fileProducerConsumer := parallel.NewRunner(enrichCmd.threads, 20000, false) - fileProducerErrors := make([][]formats.SimpleJsonError, threads) indexedFileProducerConsumer := parallel.NewRunner(enrichCmd.threads, 20000, false) - indexedFileProducerErrors := make([][]formats.SimpleJsonError, threads) fileCollectingErrorsQueue := clientutils.NewErrorsQueue(1) // Start walking on the filesystem to "produce" files that match the given pattern // while the consumer uses the indexer to index those files. - enrichCmd.prepareScanTasks(fileProducerConsumer, indexedFileProducerConsumer, scanResults, indexedFileProducerErrors, fileCollectingErrorsQueue, xrayVersion) + enrichCmd.prepareScanTasks(fileProducerConsumer, indexedFileProducerConsumer, scanResults, fileCollectingErrorsQueue, xrayVersion) enrichCmd.performScanTasks(fileProducerConsumer, indexedFileProducerConsumer) if enrichCmd.progress != nil { @@ -181,14 +174,9 @@ func (enrichCmd *EnrichCommand) Run() (err error) { } fileCollectingErr := fileCollectingErrorsQueue.GetError() - var scanErrors []formats.SimpleJsonError if fileCollectingErr != nil { - scanErrors = append(scanErrors, formats.SimpleJsonError{ErrorMessage: fileCollectingErr.Error()}) + scanResults.Error = errors.Join(scanResults.Error, fileCollectingErr) } - scanErrors = appendErrorSlice(scanErrors, fileProducerErrors) - scanErrors = appendErrorSlice(scanErrors, indexedFileProducerErrors) - - scanResults.XrayVersion = xrayVersion isxml, err := isXML(scanResults.Targets) if err != nil { @@ -207,9 +195,8 @@ func (enrichCmd *EnrichCommand) Run() (err error) { if err != nil { return err } - - if len(scanErrors) > 0 { - return errorutils.CheckErrorf(scanErrors[0].ErrorMessage) + if scanResults.GetErrors() != nil { + return errorutils.CheckErrorf(scanResults.GetErrors().Error()) } log.Info("Enrich process completed successfully.") return nil @@ -223,13 +210,13 @@ func (enrichCmd *EnrichCommand) CommandName() string { return "xr_enrich" } -func (enrichCmd *EnrichCommand) prepareScanTasks(fileProducer, indexedFileProducer parallel.Runner, cmdResults *results.SecurityCommandResults, indexedFileErrors [][]formats.SimpleJsonError, fileCollectingErrorsQueue *clientutils.ErrorsQueue, xrayVersion string) { +func (enrichCmd *EnrichCommand) prepareScanTasks(fileProducer, indexedFileProducer parallel.Runner, cmdResults *results.SecurityCommandResults, fileCollectingErrorsQueue *clientutils.ErrorsQueue, xrayVersion string) { go func() { defer fileProducer.Done() // Iterate over file-spec groups and produce indexing tasks. // When encountering an error, log and move to next group. specFiles := enrichCmd.spec.Files - artifactHandlerFunc := enrichCmd.createIndexerHandlerFunc(indexedFileProducer, cmdResults, indexedFileErrors, xrayVersion) + artifactHandlerFunc := enrichCmd.createIndexerHandlerFunc(indexedFileProducer, cmdResults, xrayVersion) taskHandler := getAddTaskToProducerFunc(fileProducer, artifactHandlerFunc) err := FileForEnriching(specFiles[0], taskHandler) @@ -240,7 +227,7 @@ func (enrichCmd *EnrichCommand) prepareScanTasks(fileProducer, indexedFileProduc }() } -func (enrichCmd *EnrichCommand) createIndexerHandlerFunc(indexedFileProducer parallel.Runner, cmdResults *results.SecurityCommandResults, indexedFileErrors [][]formats.SimpleJsonError, xrayVersion string) FileContext { +func (enrichCmd *EnrichCommand) createIndexerHandlerFunc(indexedFileProducer parallel.Runner, cmdResults *results.SecurityCommandResults, xrayVersion string) FileContext { return func(filePath string) parallel.TaskFunc { return func(threadId int) (err error) { // Add a new task to the second producer/consumer diff --git a/jas/common.go b/jas/common.go index 1831f54f..fcbb4b94 100644 --- a/jas/common.go +++ b/jas/common.go @@ -160,7 +160,7 @@ func excludeSuppressResults(sarifResults []*sarif.Result) []*sarif.Result { func addScoreToRunRules(sarifRun *sarif.Run) { for _, sarifResult := range sarifRun.Results { - if rule, err := sarifRun.GetRuleById(*sarifResult.RuleID); err == nil { + if rule, err := sarifRun.GetRuleById(sarifutils.GetResultRuleId(sarifResult)); err == nil { // Add to the rule security-severity score based on results severity severity, err := severityutils.ParseSeverity(sarifutils.GetResultLevel(sarifResult), true) if err != nil { diff --git a/jas/sast/sastscanner.go b/jas/sast/sastscanner.go index 1cf015fa..1ea54f68 100644 --- a/jas/sast/sastscanner.go +++ b/jas/sast/sastscanner.go @@ -139,13 +139,6 @@ func getResultLocationStr(result *sarif.Result) string { sarifutils.GetLocationEndColumn(location)) } -func getResultRuleId(result *sarif.Result) string { - if result.RuleID == nil { - return "" - } - return *result.RuleID -} - func getResultId(result *sarif.Result) string { - return getResultRuleId(result) + sarifutils.GetResultLevel(result) + sarifutils.GetResultMsgText(result) + getResultLocationStr(result) + return sarifutils.GetResultRuleId(result) + sarifutils.GetResultLevel(result) + sarifutils.GetResultMsgText(result) + getResultLocationStr(result) } diff --git a/tests/testdata/other/output/formats/audit_results.json b/tests/testdata/other/output/formats/audit_results.json index 7167996d..625b06b0 100644 --- a/tests/testdata/other/output/formats/audit_results.json +++ b/tests/testdata/other/output/formats/audit_results.json @@ -1315,9 +1315,9 @@ "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { - "startLine": 11, + "startLine": 10, "startColumn": 15, - "endLine": 11, + "endLine": 10, "endColumn": 15, "snippet": { "text": "AKI************" @@ -1339,9 +1339,9 @@ "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { - "startLine": 12, + "startLine": 11, "startColumn": 12, - "endLine": 12, + "endLine": 11, "endColumn": 12, "snippet": { "text": "\"Sq************" @@ -1532,9 +1532,9 @@ "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { - "startLine": 9, + "startLine": 8, "startColumn": 11, - "endLine": 9, + "endLine": 8, "endColumn": 20, "snippet": { "text": "express()" @@ -1562,9 +1562,9 @@ "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { - "startLine": 27, + "startLine": 26, "startColumn": 28, - "endLine": 27, + "endLine": 26, "endColumn": 37, "snippet": { "text": "req.query" diff --git a/tests/testdata/other/output/formats/audit_sarif.json b/tests/testdata/other/output/formats/audit_sarif.json index 701dc586..73a208da 100644 --- a/tests/testdata/other/output/formats/audit_sarif.json +++ b/tests/testdata/other/output/formats/audit_sarif.json @@ -78,7 +78,7 @@ "arguments": [ "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721283016-528285823/Secrets_1721283016/config.yaml" + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721411216-1033191970/Secrets_1721411216/config.yaml" ], "executionSuccessful": true, "workingDirectory": { @@ -223,7 +223,7 @@ "arguments": [ "/Users/assafa/.jfrog/dependencies/analyzerManager/iac_scanner/tf_scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721283016-528285823/IaC_1721283029/config.yaml" + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721411216-1033191970/IaC_1721411227/config.yaml" ], "executionSuccessful": true, "workingDirectory": { @@ -301,8 +301,8 @@ "arguments": [ "/Users/assafa/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721283016-528285823/Sast_1721283031/results.sarif", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721283016-528285823/Sast_1721283031/config.yaml" + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721411216-1033191970/Sast_1721411231/results.sarif", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721411216-1033191970/Sast_1721411231/config.yaml" ], "executionSuccessful": true, "workingDirectory": { @@ -311,66 +311,6 @@ } ], "results": [ - { - "ruleId": "js-insecure-random", - "level": "note", - "message": { - "text": "Use of Insecure Random" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" - }, - "region": { - "startLine": 136, - "startColumn": 22, - "endLine": 136, - "endColumn": 35, - "snippet": { - "text": "Math.random()" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "public.js.bootstrap.^_0.Util.getUID" - } - ] - } - ] - }, - { - "ruleId": "js-insecure-random", - "level": "note", - "message": { - "text": "Use of Insecure Random" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" - }, - "region": { - "startLine": 135, - "startColumn": 22, - "endLine": 135, - "endColumn": 35, - "snippet": { - "text": "Math.random()" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "public.js.bootstrap\u003cdot\u003ebundle.^_0.Util.getUID" - } - ] - } - ] - }, { "ruleId": "js-express-without-helmet", "level": "note", @@ -509,6 +449,66 @@ ] } ] + }, + { + "ruleId": "js-insecure-random", + "level": "note", + "message": { + "text": "Use of Insecure Random" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" + }, + "region": { + "startLine": 136, + "startColumn": 22, + "endLine": 136, + "endColumn": 35, + "snippet": { + "text": "Math.random()" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "public.js.bootstrap.^_0.Util.getUID" + } + ] + } + ] + }, + { + "ruleId": "js-insecure-random", + "level": "note", + "message": { + "text": "Use of Insecure Random" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + }, + "region": { + "startLine": 135, + "startColumn": 22, + "endLine": 135, + "endColumn": 35, + "snippet": { + "text": "Math.random()" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "public.js.bootstrap\u003cdot\u003ebundle.^_0.Util.getUID" + } + ] + } + ] } ] }, @@ -519,16 +519,29 @@ "name": "JFrog Xray SCA", "rules": [ { - "id": "CVE-2022-29078_ejs_3.1.6", + "id": "CVE-2021-23337_lodash_4.17.0", "shortDescription": { - "text": "[CVE-2022-29078] ejs 3.1.6" + "text": "[CVE-2021-23337] lodash 4.17.0" }, "help": { - "text": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Applicable | `ejs 3.1.6` | [3.1.7] |" + "text": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.2 | Not Applicable | `lodash 4.17.0` | [4.17.21] |" }, "properties": { - "security-severity": "9.8" + "security-severity": "7.2" + } + }, + { + "id": "CVE-2018-16487_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2018-16487] lodash 4.17.0" + }, + "help": { + "text": "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.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.6 | Applicable | `lodash 4.17.0` | [4.17.11] |" + }, + "properties": { + "security-severity": "5.6" } }, { @@ -557,6 +570,19 @@ "security-severity": "9.1" } }, + { + "id": "CVE-2019-1010266_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2019-1010266] lodash 4.17.0" + }, + "help": { + "text": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.11] |" + }, + "properties": { + "security-severity": "6.5" + } + }, { "id": "CVE-2020-28500_lodash_4.17.0", "shortDescription": { @@ -571,42 +597,42 @@ } }, { - "id": "CVE-2021-23337_lodash_4.17.0", + "id": "CVE-2018-3721_lodash_4.17.0", "shortDescription": { - "text": "[CVE-2021-23337] lodash 4.17.0" + "text": "[CVE-2018-3721] lodash 4.17.0" }, "help": { - "text": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.2 | Not Applicable | `lodash 4.17.0` | [4.17.21] |" + "text": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.5] |" }, "properties": { - "security-severity": "7.2" + "security-severity": "6.5" } }, { - "id": "CVE-2018-16487_lodash_4.17.0", + "id": "CVE-2022-29078_ejs_3.1.6", "shortDescription": { - "text": "[CVE-2018-16487] lodash 4.17.0" + "text": "[CVE-2022-29078] ejs 3.1.6" }, "help": { - "text": "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.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.6 | Applicable | `lodash 4.17.0` | [4.17.11] |" + "text": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Applicable | `ejs 3.1.6` | [3.1.7] |" }, "properties": { - "security-severity": "5.6" + "security-severity": "9.8" } }, { - "id": "CVE-2024-39249_async_3.2.4", + "id": "CVE-2024-33883_ejs_3.1.6", "shortDescription": { - "text": "[CVE-2024-39249] async 3.2.4" + "text": "[CVE-2024-33883] ejs 3.1.6" }, "help": { - "text": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Not Covered | `ejs 3.1.6` | No fix available |" + "text": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.9 | Not Applicable | `ejs 3.1.6` | [3.1.10] |" }, "properties": { - "security-severity": "0.0" + "security-severity": "6.9" } }, { @@ -636,59 +662,41 @@ } }, { - "id": "CVE-2018-3721_lodash_4.17.0", - "shortDescription": { - "text": "[CVE-2018-3721] lodash 4.17.0" - }, - "help": { - "text": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.5] |" - }, - "properties": { - "security-severity": "6.5" - } - }, - { - "id": "CVE-2024-33883_ejs_3.1.6", - "shortDescription": { - "text": "[CVE-2024-33883] ejs 3.1.6" - }, - "help": { - "text": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.9 | Not Applicable | `ejs 3.1.6` | [3.1.10] |" - }, - "properties": { - "security-severity": "6.9" - } - }, - { - "id": "CVE-2019-1010266_lodash_4.17.0", + "id": "CVE-2024-39249_async_3.2.4", "shortDescription": { - "text": "[CVE-2019-1010266] lodash 4.17.0" + "text": "[CVE-2024-39249] async 3.2.4" }, "help": { - "text": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.11] |" + "text": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Not Covered | `ejs 3.1.6` | No fix available |" }, "properties": { - "security-severity": "6.5" + "security-severity": "0.0" } } ], - "version": "3.98.5" + "version": "3.98.2" } }, + "invocations": [ + { + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], "results": [ { "properties": { - "applicability": "Not Covered", - "fixedVersion": "No fix available" + "applicability": "Applicable", + "fixedVersion": "[4.17.11]" }, - "ruleId": "CVE-2024-39249_async_3.2.4", - "ruleIndex": 6, - "level": "none", + "ruleId": "CVE-2018-16487_lodash_4.17.0", + "ruleIndex": 1, + "level": "warning", "message": { - "text": "[CVE-2024-39249] ejs 3.1.6" + "text": "[CVE-2018-16487] lodash 4.17.0" }, "locations": [ { @@ -703,13 +711,13 @@ { "properties": { "applicability": "Not Applicable", - "fixedVersion": "[3.1.10]" + "fixedVersion": "[4.17.19]" }, - "ruleId": "CVE-2024-33883_ejs_3.1.6", - "ruleIndex": 10, - "level": "warning", + "ruleId": "CVE-2020-8203_lodash_4.17.0", + "ruleIndex": 2, + "level": "error", "message": { - "text": "[CVE-2024-33883] ejs 3.1.6" + "text": "[CVE-2020-8203] lodash 4.17.0" }, "locations": [ { @@ -724,13 +732,13 @@ { "properties": { "applicability": "Applicable", - "fixedVersion": "No fix available" + "fixedVersion": "[4.17.12]" }, - "ruleId": "CVE-2023-29827_ejs_3.1.6", - "ruleIndex": 7, + "ruleId": "CVE-2019-10744_lodash_4.17.0", + "ruleIndex": 3, "level": "error", "message": { - "text": "[CVE-2023-29827] ejs 3.1.6" + "text": "[CVE-2019-10744] lodash 4.17.0" }, "locations": [ { @@ -744,14 +752,14 @@ }, { "properties": { - "applicability": "Applicable", - "fixedVersion": "[3.1.7]" + "applicability": "Not Covered", + "fixedVersion": "[4.17.11]" }, - "ruleId": "CVE-2022-29078_ejs_3.1.6", - "ruleIndex": 0, - "level": "error", + "ruleId": "CVE-2019-1010266_lodash_4.17.0", + "ruleIndex": 4, + "level": "warning", "message": { - "text": "[CVE-2022-29078] ejs 3.1.6" + "text": "[CVE-2019-1010266] lodash 4.17.0" }, "locations": [ { @@ -766,13 +774,13 @@ { "properties": { "applicability": "Not Applicable", - "fixedVersion": "[4.17.19]" + "fixedVersion": "[4.17.21]" }, - "ruleId": "CVE-2020-8203_lodash_4.17.0", - "ruleIndex": 1, - "level": "error", + "ruleId": "CVE-2020-28500_lodash_4.17.0", + "ruleIndex": 5, + "level": "warning", "message": { - "text": "[CVE-2020-8203] lodash 4.17.0" + "text": "[CVE-2020-28500] lodash 4.17.0" }, "locations": [ { @@ -786,14 +794,14 @@ }, { "properties": { - "applicability": "Applicable", - "fixedVersion": "[4.17.12]" + "applicability": "Not Covered", + "fixedVersion": "[4.17.5]" }, - "ruleId": "CVE-2019-10744_lodash_4.17.0", - "ruleIndex": 2, - "level": "error", + "ruleId": "CVE-2018-3721_lodash_4.17.0", + "ruleIndex": 6, + "level": "warning", "message": { - "text": "[CVE-2019-10744] lodash 4.17.0" + "text": "[CVE-2018-3721] lodash 4.17.0" }, "locations": [ { @@ -807,14 +815,14 @@ }, { "properties": { - "applicability": "Not Covered", - "fixedVersion": "[4.17.11]" + "applicability": "Not Applicable", + "fixedVersion": "[4.17.21]" }, - "ruleId": "CVE-2019-1010266_lodash_4.17.0", - "ruleIndex": 11, - "level": "warning", + "ruleId": "CVE-2021-23337_lodash_4.17.0", + "ruleIndex": 0, + "level": "error", "message": { - "text": "[CVE-2019-1010266] lodash 4.17.0" + "text": "[CVE-2021-23337] lodash 4.17.0" }, "locations": [ { @@ -828,14 +836,14 @@ }, { "properties": { - "applicability": "Not Applicable", - "fixedVersion": "[4.17.21]" + "applicability": "Applicable", + "fixedVersion": "[3.1.7]" }, - "ruleId": "CVE-2020-28500_lodash_4.17.0", - "ruleIndex": 3, - "level": "warning", + "ruleId": "CVE-2022-29078_ejs_3.1.6", + "ruleIndex": 7, + "level": "error", "message": { - "text": "[CVE-2020-28500] lodash 4.17.0" + "text": "[CVE-2022-29078] ejs 3.1.6" }, "locations": [ { @@ -849,14 +857,14 @@ }, { "properties": { - "applicability": "Not Covered", - "fixedVersion": "[4.17.5]" + "applicability": "Not Applicable", + "fixedVersion": "[3.1.10]" }, - "ruleId": "CVE-2018-3721_lodash_4.17.0", - "ruleIndex": 9, + "ruleId": "CVE-2024-33883_ejs_3.1.6", + "ruleIndex": 8, "level": "warning", "message": { - "text": "[CVE-2018-3721] lodash 4.17.0" + "text": "[CVE-2024-33883] ejs 3.1.6" }, "locations": [ { @@ -870,14 +878,14 @@ }, { "properties": { - "applicability": "Not Applicable", - "fixedVersion": "[4.17.21]" + "applicability": "Applicable", + "fixedVersion": "No fix available" }, - "ruleId": "CVE-2021-23337_lodash_4.17.0", - "ruleIndex": 4, + "ruleId": "CVE-2023-29827_ejs_3.1.6", + "ruleIndex": 9, "level": "error", "message": { - "text": "[CVE-2021-23337] lodash 4.17.0" + "text": "[CVE-2023-29827] ejs 3.1.6" }, "locations": [ { @@ -891,14 +899,14 @@ }, { "properties": { - "applicability": "Applicable", - "fixedVersion": "[4.17.11]" + "applicability": "Not Covered", + "fixedVersion": "[4.19.2], [5.0.0-beta.3]" }, - "ruleId": "CVE-2018-16487_lodash_4.17.0", - "ruleIndex": 5, + "ruleId": "CVE-2024-29041_express_4.18.2", + "ruleIndex": 10, "level": "warning", "message": { - "text": "[CVE-2018-16487] lodash 4.17.0" + "text": "[CVE-2024-29041] express 4.18.2" }, "locations": [ { @@ -913,13 +921,13 @@ { "properties": { "applicability": "Not Covered", - "fixedVersion": "[4.19.2], [5.0.0-beta.3]" + "fixedVersion": "No fix available" }, - "ruleId": "CVE-2024-29041_express_4.18.2", - "ruleIndex": 8, - "level": "warning", + "ruleId": "CVE-2024-39249_async_3.2.4", + "ruleIndex": 11, + "level": "none", "message": { - "text": "[CVE-2024-29041] express 4.18.2" + "text": "[CVE-2024-39249] ejs 3.1.6" }, "locations": [ { @@ -1067,20 +1075,6 @@ "security-severity": 6.9 } }, - { - "id": "applic_CVE-2018-3721", - "name": "CVE-2018-3721", - "shortDescription": { - "text": "Scanner for uncovered CVE-2018-3721" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, { "id": "applic_CVE-2024-29041", "name": "CVE-2024-29041", @@ -1124,6 +1118,20 @@ "security-severity": 6.9 } }, + { + "id": "applic_CVE-2018-3721", + "name": "CVE-2018-3721", + "shortDescription": { + "text": "Scanner for uncovered CVE-2018-3721" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, { "id": "applic_CVE-2024-39249", "name": "CVE-2024-39249", @@ -1147,7 +1155,7 @@ "arguments": [ "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721283016-528285823/Applicability_1721283031/config.yaml" + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721411216-1033191970/Applicability_1721411231/config.yaml" ], "executionSuccessful": true, "workingDirectory": { diff --git a/utils/formats/sarifutils/sarifutils.go b/utils/formats/sarifutils/sarifutils.go index 03dd84ea..71039d0b 100644 --- a/utils/formats/sarifutils/sarifutils.go +++ b/utils/formats/sarifutils/sarifutils.go @@ -121,6 +121,13 @@ func GetRunsByToolName(report *sarif.Report, toolName string) (filteredRuns []*s return } +func GetResultRuleId(result *sarif.Result) string { + if result.RuleID == nil { + return "" + } + return *result.RuleID +} + func GetResultMsgText(result *sarif.Result) string { if result.Message.Text != nil { return *result.Message.Text diff --git a/utils/results/common.go b/utils/results/common.go index 9f1ff3b8..c53f4192 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -63,7 +63,7 @@ func PrepareJasIssues(target string, runs []*sarif.Run, entitledForJas bool, han if err != nil { return err } - rule, err := run.GetRuleById(*result.RuleID) + rule, err := run.GetRuleById(sarifutils.GetResultRuleId(result)) if errorutils.CheckError(err) != nil { return err } @@ -268,11 +268,6 @@ func GetScaIssueId(depName, version, issueId string) string { func ConvertCvesWithApplicability(cves []services.Cve, entitledForJas bool, applicabilityRuns []*sarif.Run, components map[string]services.Component) (convertedCves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus) { convertedCves = convertCves(cves) - applicabilityStatus = jasutils.NotScanned - if !entitledForJas { - return - } - applicabilityStatus = jasutils.ApplicabilityUndetermined for i := range convertedCves { convertedCves[i].Applicability = GetCveApplicabilityField(convertedCves[i].Id, applicabilityRuns, components) } diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index c3c45c42..2d298d31 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -23,6 +23,7 @@ const ( ScaToolName = "JFrog Xray SCA" SastToolName = "USAF" IacToolName = "JFrog Terraform scanner" + // #nosec G101 -- Not credentials. SecretsToolName = "JFrog Secrets scanner" ContexualAnalysisToolName = "JFrog Applicability Scanner" ) diff --git a/utils/results/results.go b/utils/results/results.go index 122b2c4c..2eed3611 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -46,7 +46,7 @@ type TargetResults struct { } type ScaScanResults struct { - ScanTarget + // ScanTarget IsMultipleRootProject *bool `json:"is_multiple_root_project,omitempty"` // Target of the scan Descriptors []string `json:"descriptors,omitempty"` @@ -158,6 +158,7 @@ func (r *SecurityCommandResults) NewScanResults(target ScanTarget) *TargetResult if r.EntitledForJas { targetResults.JasResults = &JasScansResults{} } + r.targetsMutex.Lock() r.Targets = append(r.Targets, targetResults) r.targetsMutex.Unlock() @@ -223,19 +224,17 @@ func (sr *TargetResults) AddError(err error) { func (sr *TargetResults) SetDescriptors(descriptors ...string) *TargetResults { if sr.ScaResults == nil { - return sr + sr.ScaResults = &ScaScanResults{} } sr.ScaResults.Descriptors = descriptors return sr } func (sr *TargetResults) NewScaScanResults(responses ...services.ScanResponse) *ScaScanResults { - results := sr.ScaResults - if results == nil { - results = &ScaScanResults{} - sr.ScaResults = results + if sr.ScaResults == nil { + sr.ScaResults = &ScaScanResults{} } - sr.ScaResults.XrayResults = append(results.XrayResults, responses...) + sr.ScaResults.XrayResults = append(sr.ScaResults.XrayResults, responses...) return sr.ScaResults } diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index 5df5136a..011f942b 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -154,7 +154,7 @@ func validateSarifRun(t *testing.T, exactMatch bool, expected, actual *sarif.Run // validate results for _, expectedResult := range expected.Results { result := getResultByResultId(expectedResult, actual.Results) - if !assert.NotNil(t, result, fmt.Sprintf("Run tool %s: Expected result with rule ID %s not found", expected.Tool.Driver.Name, *expectedResult.RuleID)) { + if !assert.NotNil(t, result, fmt.Sprintf("Run tool %s: Expected result with rule ID %s not found", expected.Tool.Driver.Name, sarifutils.GetResultRuleId(expectedResult))) { continue } validateSarifResult(t, exactMatch, expected.Tool.Driver.Name, expectedResult, result) @@ -175,22 +175,36 @@ func validateSarifRule(t *testing.T, exactMatch bool, toolName string, expected, func getResultByResultId(expected *sarif.Result, actual []*sarif.Result) *sarif.Result { for _, result := range actual { - // TODO: Need to be improved to handle secrets results (have one result for each location with same info, so need to compare the locations) - if result.RuleID == expected.RuleID && - len(result.Locations) == len(expected.Locations) && - sarifutils.GetResultMsgText(result) == sarifutils.GetResultMsgText(expected) { + if isPotentialSimilarResults(expected, result) && hasSameLocations(expected, result) { return result } } return nil } +func isPotentialSimilarResults(expected, actual *sarif.Result) bool { + return sarifutils.GetResultRuleId(actual) == sarifutils.GetResultRuleId(expected) && sarifutils.GetResultMsgText(actual) == sarifutils.GetResultMsgText(expected) +} + +func hasSameLocations(expected, actual *sarif.Result) bool { + if len(expected.Locations) != len(actual.Locations) { + return false + } + for _, expectedLocation := range expected.Locations { + location := getLocationById(expectedLocation, actual.Locations) + if location == nil { + return false + } + } + return true +} + func validateSarifResult(t *testing.T, exactMatch bool, toolName string, expected, actual *sarif.Result) { validateContent(t, exactMatch, - StringValidation{Expected: sarifutils.GetResultLevel(expected), Actual: sarifutils.GetResultLevel(actual), Msg: fmt.Sprintf("Run tool %s: Result level mismatch for rule %s", toolName, *expected.RuleID)}, + StringValidation{Expected: sarifutils.GetResultLevel(expected), Actual: sarifutils.GetResultLevel(actual), Msg: fmt.Sprintf("Run tool %s: Result level mismatch for rule %s", toolName, sarifutils.GetResultRuleId(expected))}, ) // validate properties - validateSarifProperties(t, exactMatch, expected.Properties, actual.Properties, toolName, *expected.RuleID) + validateSarifProperties(t, exactMatch, expected.Properties, actual.Properties, toolName, sarifutils.GetResultRuleId(expected)) // validate locations for _, expectedLocation := range expected.Locations { location := getLocationById(expectedLocation, actual.Locations) diff --git a/utils/validations/test_validate_simple_json.go b/utils/validations/test_validate_simple_json.go index d5a3bf38..9627130f 100644 --- a/utils/validations/test_validate_simple_json.go +++ b/utils/validations/test_validate_simple_json.go @@ -187,10 +187,12 @@ func validateCveRows(t *testing.T, issueId string, exactMatch bool, expected, ac } func validateCveRow(t *testing.T, issueId string, exactMatch bool, expected, actual formats.CveRow) { - validateContent(t, exactMatch, + if !validateContent(t, exactMatch, StringValidation{Expected: expected.CvssV2, Actual: actual.CvssV2, Msg: fmt.Sprintf("IssueId %s: Cve %s: CvssV2 mismatch", issueId, expected.Id)}, StringValidation{Expected: expected.CvssV3, Actual: actual.CvssV3, Msg: fmt.Sprintf("IssueId %s: Cve %s: CvssV3 mismatch", issueId, expected.Id)}, - ) + ) { + return + } if ValidatePointersAndNotNil(t, exactMatch, PointerValidation[formats.Applicability]{Expected: expected.Applicability, Actual: actual.Applicability, Msg: fmt.Sprintf("IssueId %s: Cve %s: Applicability mismatch", issueId, expected.Id)}) { validateContent(t, exactMatch, StringValidation{Expected: expected.Applicability.Status, Actual: actual.Applicability.Status, Msg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.Status mismatch", issueId, expected.Id)}, diff --git a/utils/validations/test_validation.go b/utils/validations/test_validation.go index 1c59ddee..a0c3d9d1 100644 --- a/utils/validations/test_validation.go +++ b/utils/validations/test_validation.go @@ -65,7 +65,7 @@ func validateStrContent(t *testing.T, expected, actual string, actualValue bool, } func (sv StringValidation) ErrMsgs(_ *testing.T) []string { - return errMsg(sv.Expected, sv.Actual, sv.Msg) + return []string{sv.Msg} } type NumberValidation[T any] struct { @@ -90,7 +90,7 @@ func validateNumberContent(t *testing.T, expected, actual interface{}, actualVal } func (nvp NumberValidation[T]) ErrMsgs(_ *testing.T) []string { - return errMsg(fmt.Sprintf("%v", nvp.Expected), fmt.Sprintf("%v", nvp.Actual), nvp.Msg) + return []string{nvp.Msg} } type PointerValidation[T any] struct { From 2ac4d7bef273df0e66b391f5111dc680bb2f6d68 Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 21 Jul 2024 17:10:01 +0300 Subject: [PATCH 30/82] continue fix tests --- .../simplejsonparser/simplejsonparser_test.go | 10 ++++++++++ utils/xsc/analyticsmetrics.go | 2 +- utils/xsc/analyticsmetrics_test.go | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go index 1d19055d..98114d9f 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go @@ -457,6 +457,16 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { ImpactedDependencyName: "component-B", }, }, + + { + IssueId: "XRAY-2", + Summary: "summary-2", + Severity: "Low", + WatchName: "watch-1", + ViolationType: "license", + LicenseKey: "license-1", + Components: map[string]services.Component{"component-B": {}}, + }, }, }, { diff --git a/utils/xsc/analyticsmetrics.go b/utils/xsc/analyticsmetrics.go index 5f45eccd..a26b8ff4 100644 --- a/utils/xsc/analyticsmetrics.go +++ b/utils/xsc/analyticsmetrics.go @@ -164,7 +164,7 @@ func (ams *AnalyticsMetricsService) CreateXscAnalyticsGeneralEventFinalizeFromAu if auditResults.GetErrors() != nil { eventStatus = xscservices.Failed } - summary, err := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{}).ConvertToSummary(auditResults) + summary, err := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{}).ConvertToSummary(auditResults) if err != nil { log.Warn(fmt.Sprintf("Failed to convert audit results to summary. %s", err.Error())) } diff --git a/utils/xsc/analyticsmetrics_test.go b/utils/xsc/analyticsmetrics_test.go index 561300a7..3574c424 100644 --- a/utils/xsc/analyticsmetrics_test.go +++ b/utils/xsc/analyticsmetrics_test.go @@ -107,7 +107,7 @@ func TestAnalyticsMetricsService_createAuditResultsFromXscAnalyticsBasicGeneralE } func getDummyContentForGeneralEvent(withJas, withErr bool) *results.SecurityCommandResults { - vulnerabilities := []services.Vulnerability{{IssueId: "XRAY-ID", Cves: []services.Cve{{Id: "CVE-123"}}, Components: map[string]services.Component{"issueId_2_direct_dependency": {}}}} + vulnerabilities := []services.Vulnerability{{IssueId: "XRAY-ID", Severity: "medium", Cves: []services.Cve{{Id: "CVE-123"}}, Components: map[string]services.Component{"issueId_2_direct_dependency": {}}}} cmdResults := results.NewCommandResults("", true) scanResults := cmdResults.NewScanResults(results.ScanTarget{Target: "target"}) From 3a3e0597b721cb3118e3ee7af64bccdbbf10243a Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 22 Jul 2024 17:14:58 +0300 Subject: [PATCH 31/82] continue fix tests --- .../other/output/formats/audit_sarif.json | 531 ++++++++---------- utils/formats/sarifutils/sarifutils.go | 9 + utils/formats/sarifutils/test_sarifutils.go | 18 +- .../conversion/sarifparser/sarifparser.go | 6 +- .../simplejsonparser/simplejsonparser_test.go | 167 ++++-- utils/results/results.go | 2 +- 6 files changed, 371 insertions(+), 362 deletions(-) diff --git a/tests/testdata/other/output/formats/audit_sarif.json b/tests/testdata/other/output/formats/audit_sarif.json index 73a208da..8da7265a 100644 --- a/tests/testdata/other/output/formats/audit_sarif.json +++ b/tests/testdata/other/output/formats/audit_sarif.json @@ -78,7 +78,7 @@ "arguments": [ "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721411216-1033191970/Secrets_1721411216/config.yaml" + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721657068-1669763637/Secrets_1721657068/config.yaml" ], "executionSuccessful": true, "workingDirectory": { @@ -223,7 +223,7 @@ "arguments": [ "/Users/assafa/.jfrog/dependencies/analyzerManager/iac_scanner/tf_scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721411216-1033191970/IaC_1721411227/config.yaml" + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721657068-1669763637/IaC_1721657081/config.yaml" ], "executionSuccessful": true, "workingDirectory": { @@ -301,8 +301,8 @@ "arguments": [ "/Users/assafa/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721411216-1033191970/Sast_1721411231/results.sarif", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721411216-1033191970/Sast_1721411231/config.yaml" + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721657068-1669763637/Sast_1721657083/results.sarif", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721657068-1669763637/Sast_1721657083/config.yaml" ], "executionSuccessful": true, "workingDirectory": { @@ -311,6 +311,66 @@ } ], "results": [ + { + "ruleId": "js-insecure-random", + "level": "note", + "message": { + "text": "Use of Insecure Random" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" + }, + "region": { + "startLine": 136, + "startColumn": 22, + "endLine": 136, + "endColumn": 35, + "snippet": { + "text": "Math.random()" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "public.js.bootstrap.^_0.Util.getUID" + } + ] + } + ] + }, + { + "ruleId": "js-insecure-random", + "level": "note", + "message": { + "text": "Use of Insecure Random" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + }, + "region": { + "startLine": 135, + "startColumn": 22, + "endLine": 135, + "endColumn": 35, + "snippet": { + "text": "Math.random()" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "public.js.bootstrap\u003cdot\u003ebundle.^_0.Util.getUID" + } + ] + } + ] + }, { "ruleId": "js-express-without-helmet", "level": "note", @@ -449,66 +509,6 @@ ] } ] - }, - { - "ruleId": "js-insecure-random", - "level": "note", - "message": { - "text": "Use of Insecure Random" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" - }, - "region": { - "startLine": 136, - "startColumn": 22, - "endLine": 136, - "endColumn": 35, - "snippet": { - "text": "Math.random()" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "public.js.bootstrap.^_0.Util.getUID" - } - ] - } - ] - }, - { - "ruleId": "js-insecure-random", - "level": "note", - "message": { - "text": "Use of Insecure Random" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" - }, - "region": { - "startLine": 135, - "startColumn": 22, - "endLine": 135, - "endColumn": 35, - "snippet": { - "text": "Math.random()" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "public.js.bootstrap\u003cdot\u003ebundle.^_0.Util.getUID" - } - ] - } - ] } ] }, @@ -518,6 +518,19 @@ "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sca", "name": "JFrog Xray SCA", "rules": [ + { + "id": "CVE-2018-3721_lodash_4.17.0", + "shortDescription": { + "text": "[CVE-2018-3721] lodash 4.17.0" + }, + "help": { + "text": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.5] |" + }, + "properties": { + "security-severity": "6.5" + } + }, { "id": "CVE-2021-23337_lodash_4.17.0", "shortDescription": { @@ -538,140 +551,127 @@ }, "help": { "text": "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.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.6 | Applicable | `lodash 4.17.0` | [4.17.11] |" + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.6 | Not Applicable | `lodash 4.17.0` | [4.17.11] |" }, "properties": { "security-severity": "5.6" } }, { - "id": "CVE-2020-8203_lodash_4.17.0", + "id": "CVE-2024-39249_async_3.2.4", "shortDescription": { - "text": "[CVE-2020-8203] lodash 4.17.0" + "text": "[CVE-2024-39249] async 3.2.4" }, "help": { - "text": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.4 | Not Applicable | `lodash 4.17.0` | [4.17.19] |" + "text": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Not Covered | `ejs 3.1.6` | No fix available |" }, "properties": { - "security-severity": "7.4" + "security-severity": "0.0" } }, { - "id": "CVE-2019-10744_lodash_4.17.0", + "id": "CVE-2024-29041_express_4.18.2", "shortDescription": { - "text": "[CVE-2019-10744] lodash 4.17.0" + "text": "[CVE-2024-29041] express 4.18.2" }, "help": { - "text": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.1 | Applicable | `lodash 4.17.0` | [4.17.12] |" + "text": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.1 | Not Covered | `express 4.18.2` | [4.19.2], [5.0.0-beta.3] |" }, "properties": { - "security-severity": "9.1" + "security-severity": "6.1" } }, { - "id": "CVE-2019-1010266_lodash_4.17.0", + "id": "CVE-2024-33883_ejs_3.1.6", "shortDescription": { - "text": "[CVE-2019-1010266] lodash 4.17.0" + "text": "[CVE-2024-33883] ejs 3.1.6" }, "help": { - "text": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.11] |" + "text": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.9 | Not Applicable | `ejs 3.1.6` | [3.1.10] |" }, "properties": { - "security-severity": "6.5" + "security-severity": "6.9" } }, { - "id": "CVE-2020-28500_lodash_4.17.0", + "id": "CVE-2020-8203_lodash_4.17.0", "shortDescription": { - "text": "[CVE-2020-28500] lodash 4.17.0" + "text": "[CVE-2020-8203] lodash 4.17.0" }, "help": { - "text": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.3 | Not Applicable | `lodash 4.17.0` | [4.17.21] |" + "text": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.4 | Not Applicable | `lodash 4.17.0` | [4.17.19] |" }, "properties": { - "security-severity": "5.3" + "security-severity": "7.4" } }, { - "id": "CVE-2018-3721_lodash_4.17.0", + "id": "CVE-2020-28500_lodash_4.17.0", "shortDescription": { - "text": "[CVE-2018-3721] lodash 4.17.0" + "text": "[CVE-2020-28500] lodash 4.17.0" }, "help": { - "text": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.5] |" + "text": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.3 | Not Applicable | `lodash 4.17.0` | [4.17.21] |" }, "properties": { - "security-severity": "6.5" + "security-severity": "5.3" } }, { - "id": "CVE-2022-29078_ejs_3.1.6", + "id": "CVE-2023-29827_ejs_3.1.6", "shortDescription": { - "text": "[CVE-2022-29078] ejs 3.1.6" + "text": "[CVE-2023-29827] ejs 3.1.6" }, "help": { - "text": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Applicable | `ejs 3.1.6` | [3.1.7] |" + "text": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Applicable | `ejs 3.1.6` | No fix available |" }, "properties": { "security-severity": "9.8" } }, { - "id": "CVE-2024-33883_ejs_3.1.6", - "shortDescription": { - "text": "[CVE-2024-33883] ejs 3.1.6" - }, - "help": { - "text": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.9 | Not Applicable | `ejs 3.1.6` | [3.1.10] |" - }, - "properties": { - "security-severity": "6.9" - } - }, - { - "id": "CVE-2023-29827_ejs_3.1.6", + "id": "CVE-2022-29078_ejs_3.1.6", "shortDescription": { - "text": "[CVE-2023-29827] ejs 3.1.6" + "text": "[CVE-2022-29078] ejs 3.1.6" }, "help": { - "text": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Applicable | `ejs 3.1.6` | No fix available |" + "text": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Not Applicable | `ejs 3.1.6` | [3.1.7] |" }, "properties": { "security-severity": "9.8" } }, { - "id": "CVE-2024-29041_express_4.18.2", + "id": "CVE-2019-10744_lodash_4.17.0", "shortDescription": { - "text": "[CVE-2024-29041] express 4.18.2" + "text": "[CVE-2019-10744] lodash 4.17.0" }, "help": { - "text": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.1 | Not Covered | `express 4.18.2` | [4.19.2], [5.0.0-beta.3] |" + "text": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.1 | Not Applicable | `lodash 4.17.0` | [4.17.12] |" }, "properties": { - "security-severity": "6.1" + "security-severity": "9.1" } }, { - "id": "CVE-2024-39249_async_3.2.4", + "id": "CVE-2019-1010266_lodash_4.17.0", "shortDescription": { - "text": "[CVE-2024-39249] async 3.2.4" + "text": "[CVE-2019-1010266] lodash 4.17.0" }, "help": { - "text": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Not Covered | `ejs 3.1.6` | No fix available |" + "text": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.11] |" }, "properties": { - "security-severity": "0.0" + "security-severity": "6.5" } } ], @@ -689,20 +689,20 @@ "results": [ { "properties": { - "applicability": "Applicable", - "fixedVersion": "[4.17.11]" + "applicability": "Not Covered", + "fixedVersion": "[4.19.2], [5.0.0-beta.3]" }, - "ruleId": "CVE-2018-16487_lodash_4.17.0", - "ruleIndex": 1, + "ruleId": "CVE-2024-29041_express_4.18.2", + "ruleIndex": 4, "level": "warning", "message": { - "text": "[CVE-2018-16487] lodash 4.17.0" + "text": "[CVE-2024-29041] express 4.18.2" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -710,20 +710,20 @@ }, { "properties": { - "applicability": "Not Applicable", - "fixedVersion": "[4.17.19]" + "applicability": "Applicable", + "fixedVersion": "No fix available" }, - "ruleId": "CVE-2020-8203_lodash_4.17.0", - "ruleIndex": 2, + "ruleId": "CVE-2023-29827_ejs_3.1.6", + "ruleIndex": 8, "level": "error", "message": { - "text": "[CVE-2020-8203] lodash 4.17.0" + "text": "[CVE-2023-29827] ejs 3.1.6" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -731,20 +731,20 @@ }, { "properties": { - "applicability": "Applicable", - "fixedVersion": "[4.17.12]" + "applicability": "Not Applicable", + "fixedVersion": "[3.1.7]" }, - "ruleId": "CVE-2019-10744_lodash_4.17.0", - "ruleIndex": 3, + "ruleId": "CVE-2022-29078_ejs_3.1.6", + "ruleIndex": 9, "level": "error", "message": { - "text": "[CVE-2019-10744] lodash 4.17.0" + "text": "[CVE-2022-29078] ejs 3.1.6" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -752,20 +752,20 @@ }, { "properties": { - "applicability": "Not Covered", - "fixedVersion": "[4.17.11]" + "applicability": "Not Applicable", + "fixedVersion": "[3.1.10]" }, - "ruleId": "CVE-2019-1010266_lodash_4.17.0", - "ruleIndex": 4, + "ruleId": "CVE-2024-33883_ejs_3.1.6", + "ruleIndex": 5, "level": "warning", "message": { - "text": "[CVE-2019-1010266] lodash 4.17.0" + "text": "[CVE-2024-33883] ejs 3.1.6" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -774,19 +774,19 @@ { "properties": { "applicability": "Not Applicable", - "fixedVersion": "[4.17.21]" + "fixedVersion": "[4.17.19]" }, - "ruleId": "CVE-2020-28500_lodash_4.17.0", - "ruleIndex": 5, - "level": "warning", + "ruleId": "CVE-2020-8203_lodash_4.17.0", + "ruleIndex": 6, + "level": "error", "message": { - "text": "[CVE-2020-28500] lodash 4.17.0" + "text": "[CVE-2020-8203] lodash 4.17.0" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -794,20 +794,20 @@ }, { "properties": { - "applicability": "Not Covered", - "fixedVersion": "[4.17.5]" + "applicability": "Not Applicable", + "fixedVersion": "[4.17.12]" }, - "ruleId": "CVE-2018-3721_lodash_4.17.0", - "ruleIndex": 6, - "level": "warning", + "ruleId": "CVE-2019-10744_lodash_4.17.0", + "ruleIndex": 10, + "level": "error", "message": { - "text": "[CVE-2018-3721] lodash 4.17.0" + "text": "[CVE-2019-10744] lodash 4.17.0" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -815,20 +815,20 @@ }, { "properties": { - "applicability": "Not Applicable", - "fixedVersion": "[4.17.21]" + "applicability": "Not Covered", + "fixedVersion": "[4.17.11]" }, - "ruleId": "CVE-2021-23337_lodash_4.17.0", - "ruleIndex": 0, - "level": "error", + "ruleId": "CVE-2019-1010266_lodash_4.17.0", + "ruleIndex": 11, + "level": "warning", "message": { - "text": "[CVE-2021-23337] lodash 4.17.0" + "text": "[CVE-2019-1010266] lodash 4.17.0" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -836,20 +836,20 @@ }, { "properties": { - "applicability": "Applicable", - "fixedVersion": "[3.1.7]" + "applicability": "Not Applicable", + "fixedVersion": "[4.17.21]" }, - "ruleId": "CVE-2022-29078_ejs_3.1.6", + "ruleId": "CVE-2020-28500_lodash_4.17.0", "ruleIndex": 7, - "level": "error", + "level": "warning", "message": { - "text": "[CVE-2022-29078] ejs 3.1.6" + "text": "[CVE-2020-28500] lodash 4.17.0" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -857,20 +857,20 @@ }, { "properties": { - "applicability": "Not Applicable", - "fixedVersion": "[3.1.10]" + "applicability": "Not Covered", + "fixedVersion": "[4.17.5]" }, - "ruleId": "CVE-2024-33883_ejs_3.1.6", - "ruleIndex": 8, + "ruleId": "CVE-2018-3721_lodash_4.17.0", + "ruleIndex": 0, "level": "warning", "message": { - "text": "[CVE-2024-33883] ejs 3.1.6" + "text": "[CVE-2018-3721] lodash 4.17.0" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -878,20 +878,20 @@ }, { "properties": { - "applicability": "Applicable", - "fixedVersion": "No fix available" + "applicability": "Not Applicable", + "fixedVersion": "[4.17.21]" }, - "ruleId": "CVE-2023-29827_ejs_3.1.6", - "ruleIndex": 9, + "ruleId": "CVE-2021-23337_lodash_4.17.0", + "ruleIndex": 1, "level": "error", "message": { - "text": "[CVE-2023-29827] ejs 3.1.6" + "text": "[CVE-2021-23337] lodash 4.17.0" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -899,20 +899,20 @@ }, { "properties": { - "applicability": "Not Covered", - "fixedVersion": "[4.19.2], [5.0.0-beta.3]" + "applicability": "Not Applicable", + "fixedVersion": "[4.17.11]" }, - "ruleId": "CVE-2024-29041_express_4.18.2", - "ruleIndex": 10, + "ruleId": "CVE-2018-16487_lodash_4.17.0", + "ruleIndex": 2, "level": "warning", "message": { - "text": "[CVE-2024-29041] express 4.18.2" + "text": "[CVE-2018-16487] lodash 4.17.0" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -924,7 +924,7 @@ "fixedVersion": "No fix available" }, "ruleId": "CVE-2024-39249_async_3.2.4", - "ruleIndex": 11, + "ruleIndex": 3, "level": "none", "message": { "text": "[CVE-2024-39249] ejs 3.1.6" @@ -933,7 +933,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -958,8 +958,8 @@ "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." }, "properties": { - "applicability": "applicable", - "conclusion": "negative", + "applicability": "not_applicable", + "conclusion": "positive", "security-severity": 6.9 } }, @@ -974,8 +974,8 @@ "markdown": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." }, "properties": { - "applicability": "applicable", - "conclusion": "negative", + "applicability": "not_applicable", + "conclusion": "positive", "security-severity": 6.9 } }, @@ -1038,8 +1038,8 @@ "markdown": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." }, "properties": { - "applicability": "applicable", - "conclusion": "negative", + "applicability": "not_applicable", + "conclusion": "positive", "security-severity": 6.9 } }, @@ -1076,10 +1076,10 @@ } }, { - "id": "applic_CVE-2024-29041", - "name": "CVE-2024-29041", + "id": "applic_CVE-2018-3721", + "name": "CVE-2018-3721", "shortDescription": { - "text": "Scanner for uncovered CVE-2024-29041" + "text": "Scanner for uncovered CVE-2018-3721" }, "fullDescription": { "text": "", @@ -1104,32 +1104,32 @@ } }, { - "id": "applic_CVE-2024-39249", - "name": "CVE-2024-39249", + "id": "applic_CVE-2024-29041", + "name": "CVE-2024-29041", "shortDescription": { - "text": "Scanner for uncovered CVE-2024-39249" + "text": "Scanner for uncovered CVE-2024-29041" }, "fullDescription": { - "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", - "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + "text": "", + "markdown": "" }, "properties": { - "applicability": "not_covered", - "security-severity": 6.9 + "applicability": "not_covered" } }, { - "id": "applic_CVE-2018-3721", - "name": "CVE-2018-3721", + "id": "applic_CVE-2024-39249", + "name": "CVE-2024-39249", "shortDescription": { - "text": "Scanner for uncovered CVE-2018-3721" + "text": "Scanner for uncovered CVE-2024-39249" }, "fullDescription": { - "text": "", - "markdown": "" + "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", + "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." }, "properties": { - "applicability": "not_covered" + "applicability": "not_covered", + "security-severity": 6.9 } }, { @@ -1155,7 +1155,7 @@ "arguments": [ "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721411216-1033191970/Applicability_1721411231/config.yaml" + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721657068-1669763637/Applicability_1721657083/config.yaml" ], "executionSuccessful": true, "workingDirectory": { @@ -1167,7 +1167,7 @@ { "ruleId": "applic_CVE-2018-16487", "message": { - "text": "The vulnerable function merge/mergeWith/defaultsDeep is called with external input" + "text": "Prototype pollution `Object.freeze` remediation was detected" }, "locations": [ { @@ -1176,12 +1176,12 @@ "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { - "startLine": 33, - "startColumn": 2, - "endLine": 33, - "endColumn": 34, + "startLine": 4, + "startColumn": 0, + "endLine": 4, + "endColumn": 31, "snippet": { - "text": "lodash.defaultsDeep(data, input)" + "text": "Object.freeze(Object.prototype)" } } } @@ -1190,32 +1190,15 @@ }, { "ruleId": "applic_CVE-2018-16487", + "kind": "pass", "message": { - "text": "The vulnerable function merge/mergeWith/defaultsDeep is called with external input" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 6, - "startColumn": 0, - "endLine": 6, - "endColumn": 32, - "snippet": { - "text": "lodash.defaultsDeep({}, evilsrc)" - } - } - } - } - ] + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + } }, { "ruleId": "applic_CVE-2019-10744", "message": { - "text": "The vulnerable function defaultsDeep is called with external input" + "text": "Prototype pollution `Object.freeze` remediation was detected" }, "locations": [ { @@ -1224,12 +1207,12 @@ "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { - "startLine": 33, - "startColumn": 2, - "endLine": 33, - "endColumn": 34, + "startLine": 4, + "startColumn": 0, + "endLine": 4, + "endColumn": 31, "snippet": { - "text": "lodash.defaultsDeep(data, input)" + "text": "Object.freeze(Object.prototype)" } } } @@ -1238,27 +1221,10 @@ }, { "ruleId": "applic_CVE-2019-10744", + "kind": "pass", "message": { - "text": "The vulnerable function defaultsDeep is called with external input" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 6, - "startColumn": 0, - "endLine": 6, - "endColumn": 32, - "snippet": { - "text": "lodash.defaultsDeep({}, evilsrc)" - } - } - } - } - ] + "text": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." + } }, { "ruleId": "applic_CVE-2020-28500", @@ -1284,7 +1250,7 @@ { "ruleId": "applic_CVE-2022-29078", "message": { - "text": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" + "text": "Prototype pollution `Object.freeze` remediation was detected" }, "locations": [ { @@ -1293,12 +1259,12 @@ "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { - "startLine": 14, + "startLine": 4, "startColumn": 0, - "endLine": 14, - "endColumn": 29, + "endLine": 4, + "endColumn": 31, "snippet": { - "text": "app.set('view engine', 'ejs')" + "text": "Object.freeze(Object.prototype)" } } } @@ -1307,27 +1273,10 @@ }, { "ruleId": "applic_CVE-2022-29078", + "kind": "pass", "message": { - "text": "The vulnerable function render is called" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 26, - "startColumn": 2, - "endLine": 26, - "endColumn": 37, - "snippet": { - "text": "res.render('pages/index',req.query)" - } - } - } - } - ] + "text": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + } }, { "ruleId": "applic_CVE-2024-33883", diff --git a/utils/formats/sarifutils/sarifutils.go b/utils/formats/sarifutils/sarifutils.go index 71039d0b..2625b981 100644 --- a/utils/formats/sarifutils/sarifutils.go +++ b/utils/formats/sarifutils/sarifutils.go @@ -242,6 +242,15 @@ func IsResultKindNotPass(result *sarif.Result) bool { return !(result.Kind != nil && *result.Kind == "pass") } +func GetRuleById(run *sarif.Run, ruleId string) *sarif.ReportingDescriptor { + for _, rule := range GetRunRules(run) { + if rule.ID == ruleId { + return rule + } + } + return nil +} + func GetRuleFullDescription(rule *sarif.ReportingDescriptor) string { if rule.FullDescription != nil && rule.FullDescription.Text != nil { return *rule.FullDescription.Text diff --git a/utils/formats/sarifutils/test_sarifutils.go b/utils/formats/sarifutils/test_sarifutils.go index 2de6c19e..26245512 100644 --- a/utils/formats/sarifutils/test_sarifutils.go +++ b/utils/formats/sarifutils/test_sarifutils.go @@ -1,6 +1,8 @@ package sarifutils -import "github.com/owenrumney/go-sarif/v2/sarif" +import ( + "github.com/owenrumney/go-sarif/v2/sarif" +) func CreateRunWithDummyResults(results ...*sarif.Result) *sarif.Run { run := sarif.NewRunWithInformationURI("", "") @@ -13,14 +15,14 @@ func CreateRunWithDummyResults(results ...*sarif.Result) *sarif.Run { return run } -func CreateRunWithDummyResultAndRuleProperties(property, value string, result *sarif.Result) *sarif.Run { - run := sarif.NewRunWithInformationURI("", "") - if result.RuleID != nil { - run.AddRule(*result.RuleID) +func CreateRunWithDummyResultAndRuleProperties(property, value string, results ...*sarif.Result) *sarif.Run { + run := CreateRunWithDummyResults(results...) + for _, result := range results { + if rule := GetRuleById(run, GetResultRuleId(result)); rule != nil { + rule.Properties = make(sarif.Properties) + rule.Properties[property] = value + } } - run.AddResult(result) - run.Tool.Driver.Rules[0].Properties = make(sarif.Properties) - run.Tool.Driver.Rules[0].Properties[property] = value return run } diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index 2d298d31..2d01ca71 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -20,9 +20,9 @@ const ( FixedVersionSarifPropertyKey = "fixedVersion" WatchSarifPropertyKey = "watch" - ScaToolName = "JFrog Xray SCA" - SastToolName = "USAF" - IacToolName = "JFrog Terraform scanner" + ScaToolName = "JFrog Xray SCA" + SastToolName = "USAF" + IacToolName = "JFrog Terraform scanner" // #nosec G101 -- Not credentials. SecretsToolName = "JFrog Secrets scanner" ContexualAnalysisToolName = "JFrog Applicability Scanner" diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go index 98114d9f..08e53a3f 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go @@ -335,9 +335,13 @@ func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { target: "target", entitledForJas: true, applicablityRuns: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateDummyPassingResult("applic_CVE-1"), - sarifutils.CreateResultWithLocations("applic_CVE-2", "applic_CVE-2", "note", sarifutils.CreateLocation("target/file", 0, 0, 0, 0, "snippet")), + sarifutils.CreateRunWithDummyResultAndRuleProperties( + "applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_CVE-1"), + ).WithInvocations([]*sarif.Invocation{ + sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target")), + }), + sarifutils.CreateRunWithDummyResultAndRuleProperties( + "applicability", "applicable", sarifutils.CreateResultWithLocations("applic_CVE-2", "applic_CVE-2", "note", sarifutils.CreateLocation("target/file", 0, 0, 0, 0, "snippet")), ).WithInvocations([]*sarif.Invocation{ sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target")), }), @@ -434,108 +438,153 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { target: "target", expectedSecurityOutput: []formats.VulnerabilityOrViolationRow{ { - Summary: "summary-1", - IssueId: "XRAY-1", + Summary: "summary-1", + IssueId: "XRAY-1", + Cves: []formats.CveRow{{Id: "CVE-1"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High"}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 17}, ImpactedDependencyName: "component-A", + // Direct + Components: []formats.ComponentRow{{ + Name: "component-A", + Location: &formats.Location{File: "target"}, + }}, }, + ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-A"}}}, }, { - Summary: "summary-1", - IssueId: "XRAY-1", + Summary: "summary-1", + IssueId: "XRAY-1", + Cves: []formats.CveRow{{Id: "CVE-1"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High"}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 17}, ImpactedDependencyName: "component-B", + // Direct + Components: []formats.ComponentRow{{ + Name: "component-B", + Location: &formats.Location{File: "target"}, + }}, }, + ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-B"}}}, }, { - Summary: "summary-2", - IssueId: "XRAY-2", + Summary: "summary-2", + IssueId: "XRAY-2", + Cves: []formats.CveRow{{Id: "CVE-2"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low"}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 11}, ImpactedDependencyName: "component-B", + // Direct + Components: []formats.ComponentRow{{ + Name: "component-B", + Location: &formats.Location{File: "target"}, + }}, }, + ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-B"}}}, }, - + }, + expectedLicenseOutput: []formats.LicenseRow{ { - IssueId: "XRAY-2", - Summary: "summary-2", - Severity: "Low", - WatchName: "watch-1", - ViolationType: "license", - LicenseKey: "license-1", - Components: map[string]services.Component{"component-B": {}}, + LicenseKey: "license-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 11}, + ImpactedDependencyName: "component-B", + Components: []formats.ComponentRow{{Name: "component-B", Location: &formats.Location{File: "target"}}}, + }, }, }, }, { name: "Violations with applicability", - input: []services.Violation{ - { - IssueId: "XRAY-1", - Summary: "summary-1", - Severity: "High", - WatchName: "watch-1", - ViolationType: "security", - Components: map[string]services.Component{"component-A": {}, "component-B": {}}, - }, - { - IssueId: "XRAY-2", - Summary: "summary-2", - Severity: "Low", - WatchName: "watch-1", - ViolationType: "license", - LicenseKey: "license-1", - Components: map[string]services.Component{"component-B": {}}, - }, - }, + input: testScaScanViolation, target: "target", entitledForJas: true, applicablityRuns: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateDummyPassingResult("applic_CVE-1"), - sarifutils.CreateResultWithLocations("applic_CVE-2", "applic_CVE-2", "note", sarifutils.CreateLocation("target/file", 0, 0, 0, 0, "snippet")), + sarifutils.CreateRunWithDummyResultAndRuleProperties( + "applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_CVE-1"), + ).WithInvocations([]*sarif.Invocation{ + sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target")), + }), + sarifutils.CreateRunWithDummyResultAndRuleProperties( + "applicability", "applicable", sarifutils.CreateResultWithLocations("applic_CVE-2", "applic_CVE-2", "note", sarifutils.CreateLocation("target/file", 0, 0, 0, 0, "snippet")), ).WithInvocations([]*sarif.Invocation{ sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target")), }), }, expectedSecurityOutput: []formats.VulnerabilityOrViolationRow{ { - Summary: "summary-1", - IssueId: "XRAY-1", + Summary: "summary-1", + IssueId: "XRAY-1", + Applicable: jasutils.NotApplicable.String(), + Cves: []formats.CveRow{{Id: "CVE-1", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High"}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 4}, ImpactedDependencyName: "component-A", - Components: []formats.ComponentRow{{Name: "component-A", Location: &formats.Location{File: "target"}}}, + // Direct + Components: []formats.ComponentRow{{ + Name: "component-A", + Location: &formats.Location{File: "target"}, + }}, }, + ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-A"}}}, + }, + { + Summary: "summary-1", + IssueId: "XRAY-1", Applicable: jasutils.NotApplicable.String(), + Cves: []formats.CveRow{{Id: "CVE-1", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}}, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 4}, + ImpactedDependencyName: "component-B", + // Direct + Components: []formats.ComponentRow{{ + Name: "component-B", + Location: &formats.Location{File: "target"}, + }}, + }, + ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-B"}}}, }, { - Summary: "summary-1", - IssueId: "XRAY-1", + Summary: "summary-2", + IssueId: "XRAY-2", + Applicable: jasutils.Applicable.String(), + Cves: []formats.CveRow{{ + Id: "CVE-2", + Applicability: &formats.Applicability{ + Status: jasutils.Applicable.String(), + Evidence: []formats.Evidence{{ + Location: formats.Location{File: "file", StartLine: 0, StartColumn: 0, EndLine: 0, EndColumn: 0, Snippet: "snippet"}, + Reason: "applic_CVE-2", + }}, + }, + }}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High"}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 11}, ImpactedDependencyName: "component-B", - Components: []formats.ComponentRow{{Name: "component-B", Location: &formats.Location{File: "target"}}}, + // Direct + Components: []formats.ComponentRow{{ + Name: "component-B", + Location: &formats.Location{File: "target"}, + }}, }, - Applicable: jasutils.NotApplicable.String(), + ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-B"}}}, }, + }, + expectedLicenseOutput: []formats.LicenseRow{ { - Summary: "summary-2", - IssueId: "XRAY-2", + LicenseKey: "license-1", ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low"}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 9}, ImpactedDependencyName: "component-B", - Components: []formats.ComponentRow{{Name: "component-B", Location: &formats.Location{File: "target"}}}, + // Direct + Components: []formats.ComponentRow{{ + Name: "component-B", + Location: &formats.Location{File: "target"}, + }}, }, - Applicable: jasutils.Applicable.String(), }, }, }, - { - name: "Violations - override allowed licenses", - }, } for _, tc := range testCases { diff --git a/utils/results/results.go b/utils/results/results.go index 2eed3611..15c790b3 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -158,7 +158,7 @@ func (r *SecurityCommandResults) NewScanResults(target ScanTarget) *TargetResult if r.EntitledForJas { targetResults.JasResults = &JasScansResults{} } - + r.targetsMutex.Lock() r.Targets = append(r.Targets, targetResults) r.targetsMutex.Unlock() From 3f8c1df85d9e7a9b61335a905349f383d4b23769 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 23 Jul 2024 09:41:04 +0300 Subject: [PATCH 32/82] update test data --- .../other/output/formats/audit_sarif.json | 401 ------------------ 1 file changed, 401 deletions(-) diff --git a/tests/testdata/other/output/formats/audit_sarif.json b/tests/testdata/other/output/formats/audit_sarif.json index 8da7265a..87e119ee 100644 --- a/tests/testdata/other/output/formats/audit_sarif.json +++ b/tests/testdata/other/output/formats/audit_sarif.json @@ -940,407 +940,6 @@ ] } ] - }, - { - "tool": { - "driver": { - "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", - "name": "JFrog Applicability Scanner", - "rules": [ - { - "id": "applic_CVE-2018-16487", - "name": "CVE-2018-16487", - "shortDescription": { - "text": "Scanner for CVE-2018-16487" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", - "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2019-10744", - "name": "CVE-2019-10744", - "shortDescription": { - "text": "Scanner for CVE-2019-10744" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present.", - "markdown": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2020-28500", - "name": "CVE-2020-28500", - "shortDescription": { - "text": "Scanner for CVE-2020-28500" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument.", - "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2020-8203", - "name": "CVE-2020-8203", - "shortDescription": { - "text": "Scanner for CVE-2020-8203" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present.", - "markdown": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2021-23337", - "name": "CVE-2021-23337", - "shortDescription": { - "text": "Scanner for CVE-2021-23337" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument.", - "markdown": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2022-29078", - "name": "CVE-2022-29078", - "shortDescription": { - "text": "Scanner for CVE-2022-29078" - }, - "fullDescription": { - "text": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", - "markdown": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2024-33883", - "name": "CVE-2024-33883", - "shortDescription": { - "text": "Scanner for CVE-2024-33883" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable function `ejs.compile()` is called.", - "markdown": "The scanner checks whether the vulnerable function `ejs.compile()` is called." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2023-29827", - "name": "CVE-2023-29827", - "shortDescription": { - "text": "Scanner for CVE-2023-29827" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`", - "markdown": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`" - }, - "properties": { - "applicability": "applicable", - "conclusion": "negative", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2018-3721", - "name": "CVE-2018-3721", - "shortDescription": { - "text": "Scanner for uncovered CVE-2018-3721" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2019-1010266", - "name": "CVE-2019-1010266", - "shortDescription": { - "text": "Scanner for uncovered CVE-2019-1010266" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-29041", - "name": "CVE-2024-29041", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-29041" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-39249", - "name": "CVE-2024-39249", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-39249" - }, - "fullDescription": { - "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", - "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." - }, - "properties": { - "applicability": "not_covered", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2024-39249", - "name": "CVE-2024-39249", - "shortDescription": { - "text": "Scanner for indirect dependency CVE-2024-39249" - }, - "fullDescription": { - "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", - "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." - }, - "properties": { - "applicability": "not_applicable" - } - } - ], - "version": "1.0" - } - }, - "invocations": [ - { - "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", - "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721657068-1669763637/Applicability_1721657083/config.yaml" - ], - "executionSuccessful": true, - "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" - } - } - ], - "results": [ - { - "ruleId": "applic_CVE-2018-16487", - "message": { - "text": "Prototype pollution `Object.freeze` remediation was detected" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 4, - "startColumn": 0, - "endLine": 4, - "endColumn": 31, - "snippet": { - "text": "Object.freeze(Object.prototype)" - } - } - } - } - ] - }, - { - "ruleId": "applic_CVE-2018-16487", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." - } - }, - { - "ruleId": "applic_CVE-2019-10744", - "message": { - "text": "Prototype pollution `Object.freeze` remediation was detected" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 4, - "startColumn": 0, - "endLine": 4, - "endColumn": 31, - "snippet": { - "text": "Object.freeze(Object.prototype)" - } - } - } - } - ] - }, - { - "ruleId": "applic_CVE-2019-10744", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." - } - }, - { - "ruleId": "applic_CVE-2020-28500", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." - } - }, - { - "ruleId": "applic_CVE-2020-8203", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." - } - }, - { - "ruleId": "applic_CVE-2021-23337", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." - } - }, - { - "ruleId": "applic_CVE-2022-29078", - "message": { - "text": "Prototype pollution `Object.freeze` remediation was detected" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 4, - "startColumn": 0, - "endLine": 4, - "endColumn": 31, - "snippet": { - "text": "Object.freeze(Object.prototype)" - } - } - } - } - ] - }, - { - "ruleId": "applic_CVE-2022-29078", - "kind": "pass", - "message": { - "text": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." - } - }, - { - "ruleId": "applic_CVE-2024-33883", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable function `ejs.compile()` is called." - } - }, - { - "ruleId": "applic_CVE-2023-29827", - "message": { - "text": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 14, - "startColumn": 0, - "endLine": 14, - "endColumn": 29, - "snippet": { - "text": "app.set('view engine', 'ejs')" - } - } - } - } - ] - }, - { - "ruleId": "applic_CVE-2023-29827", - "message": { - "text": "The vulnerable function render is called" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 26, - "startColumn": 2, - "endLine": 26, - "endColumn": 37, - "snippet": { - "text": "res.render('pages/index',req.query)" - } - } - } - } - ] - }, - { - "ruleId": "applic_CVE-2024-39249", - "kind": "pass", - "message": { - "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." - } - } - ] } ] } \ No newline at end of file From bcdf8a0d01d07c0f3f536e0f73ba9a16723dfd5b Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 23 Jul 2024 11:08:48 +0300 Subject: [PATCH 33/82] format --- .../simplejsonparser/simplejsonparser_test.go | 24 +++++++++---------- utils/xsc/analyticsmetrics.go | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go index 08e53a3f..c4ec13be 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go @@ -438,9 +438,9 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { target: "target", expectedSecurityOutput: []formats.VulnerabilityOrViolationRow{ { - Summary: "summary-1", - IssueId: "XRAY-1", - Cves: []formats.CveRow{{Id: "CVE-1"}}, + Summary: "summary-1", + IssueId: "XRAY-1", + Cves: []formats.CveRow{{Id: "CVE-1"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 17}, ImpactedDependencyName: "component-A", @@ -453,9 +453,9 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-A"}}}, }, { - Summary: "summary-1", - IssueId: "XRAY-1", - Cves: []formats.CveRow{{Id: "CVE-1"}}, + Summary: "summary-1", + IssueId: "XRAY-1", + Cves: []formats.CveRow{{Id: "CVE-1"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 17}, ImpactedDependencyName: "component-B", @@ -468,9 +468,9 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-B"}}}, }, { - Summary: "summary-2", - IssueId: "XRAY-2", - Cves: []formats.CveRow{{Id: "CVE-2"}}, + Summary: "summary-2", + IssueId: "XRAY-2", + Cves: []formats.CveRow{{Id: "CVE-2"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 11}, ImpactedDependencyName: "component-B", @@ -489,14 +489,14 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 11}, ImpactedDependencyName: "component-B", - Components: []formats.ComponentRow{{Name: "component-B", Location: &formats.Location{File: "target"}}}, + Components: []formats.ComponentRow{{Name: "component-B", Location: &formats.Location{File: "target"}}}, }, }, }, }, { - name: "Violations with applicability", - input: testScaScanViolation, + name: "Violations with applicability", + input: testScaScanViolation, target: "target", entitledForJas: true, applicablityRuns: []*sarif.Run{ diff --git a/utils/xsc/analyticsmetrics.go b/utils/xsc/analyticsmetrics.go index a26b8ff4..5f45eccd 100644 --- a/utils/xsc/analyticsmetrics.go +++ b/utils/xsc/analyticsmetrics.go @@ -164,7 +164,7 @@ func (ams *AnalyticsMetricsService) CreateXscAnalyticsGeneralEventFinalizeFromAu if auditResults.GetErrors() != nil { eventStatus = xscservices.Failed } - summary, err := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{}).ConvertToSummary(auditResults) + summary, err := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{}).ConvertToSummary(auditResults) if err != nil { log.Warn(fmt.Sprintf("Failed to convert audit results to summary. %s", err.Error())) } From 19e1577ec57ce1676559406462a7682102f19c05 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 23 Jul 2024 11:46:23 +0300 Subject: [PATCH 34/82] fix static and tests --- commands/enrich/enrich.go | 7 ------ .../other/output/formats/audit_results.json | 3 +++ .../output/formats/audit_simple_json.json | 24 +++++++++---------- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/commands/enrich/enrich.go b/commands/enrich/enrich.go index 647a2fd9..6c85c230 100644 --- a/commands/enrich/enrich.go +++ b/commands/enrich/enrich.go @@ -308,10 +308,3 @@ func FileForEnriching(fileData spec.File, dataHandlerFunc indexFileHandlerFunc) } return errors.New("directory instead of a single file") } - -func appendErrorSlice(scanErrors []formats.SimpleJsonError, errorsToAdd [][]formats.SimpleJsonError) []formats.SimpleJsonError { - for _, errorSlice := range errorsToAdd { - scanErrors = append(scanErrors, errorSlice...) - } - return scanErrors -} diff --git a/tests/testdata/other/output/formats/audit_results.json b/tests/testdata/other/output/formats/audit_results.json index 625b06b0..ca11075d 100644 --- a/tests/testdata/other/output/formats/audit_results.json +++ b/tests/testdata/other/output/formats/audit_results.json @@ -8,6 +8,9 @@ "technology": "npm", "sca_scans": { "is_multiple_root_project": false, + "descriptors": [ + "/Users/user/ejs-frog-demo/package.json" + ], "xray_scan": [ { "scan_id": "3d90ec4b-cf33-4846-6831-4bf9576f2235", diff --git a/tests/testdata/other/output/formats/audit_simple_json.json b/tests/testdata/other/output/formats/audit_simple_json.json index a017dae7..44a43ac1 100644 --- a/tests/testdata/other/output/formats/audit_simple_json.json +++ b/tests/testdata/other/output/formats/audit_simple_json.json @@ -10,7 +10,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/Users/user/ejs-frog-demo" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -88,7 +88,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/Users/user/ejs-frog-demo" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -133,7 +133,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/Users/user/ejs-frog-demo" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -178,7 +178,7 @@ "name": "express", "version": "4.18.2", "location": { - "file": "/Users/user/ejs-frog-demo" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -224,7 +224,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/Users/user/ejs-frog-demo" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -300,7 +300,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/Users/user/ejs-frog-demo" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -377,7 +377,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/Users/user/ejs-frog-demo" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -453,7 +453,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/Users/user/ejs-frog-demo" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -523,7 +523,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/Users/user/ejs-frog-demo" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -586,7 +586,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/Users/user/ejs-frog-demo" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -663,7 +663,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/Users/user/ejs-frog-demo" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -729,7 +729,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/Users/user/ejs-frog-demo" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], From 7704abfb9595e4ca13fad312789b7c9dbc0be294 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 23 Jul 2024 11:47:37 +0300 Subject: [PATCH 35/82] fix static --- commands/enrich/enrich.go | 1 - utils/results/conversion/sarifparser/sarifparser.go | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/enrich/enrich.go b/commands/enrich/enrich.go index 6c85c230..b596163f 100644 --- a/commands/enrich/enrich.go +++ b/commands/enrich/enrich.go @@ -15,7 +15,6 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-security/commands/enrich/enrichgraph" - "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/results/output" "github.com/jfrog/jfrog-cli-security/utils/techutils" diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index 2d01ca71..6ec89fc7 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -37,6 +37,7 @@ type CmdResultsSarifConverter struct { current *sarif.Report scaCurrentRun *sarif.Run currentApplicableRuns *datastructures.Set[*sarif.Run] + // General information on the current command results entitledForJas bool xrayVersion string From 4f8a44ef2f8a1f7eeb5e1331c9bd1f7443dca997 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 23 Jul 2024 12:55:48 +0300 Subject: [PATCH 36/82] fix tests and cleanup --- commands/audit/audit.go | 4 +- commands/audit/scarunner.go | 33 -------- .../applicabilitymanager_test.go | 1 - jas/common.go | 12 ++- .../other/output/formats/audit_results.json | 46 +++++------ .../other/output/formats/audit_sarif.json | 56 ++++++------- .../output/formats/audit_simple_json.json | 24 +++--- .../other/output/formats/audit_summary.json | 2 +- .../other/output/formats/audit_table.json | 0 utils/formats/conversion.go | 78 ------------------- utils/results/common_test.go | 61 --------------- utils/results/results.go | 7 ++ 12 files changed, 77 insertions(+), 247 deletions(-) delete mode 100644 tests/testdata/other/output/formats/audit_table.json diff --git a/commands/audit/audit.go b/commands/audit/audit.go index 292969b2..3de4b28b 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -202,7 +202,7 @@ func RunAudit(auditParams *AuditParams) (cmdResults *results.SecurityCommandResu } // Initialize Results struct cmdResults = initCmdResults(entitledForJas, auditParams) - jfrogAppsConfig, err := jas.CreateJFrogAppsConfig(auditParams.workingDirs) + jfrogAppsConfig, err := jas.CreateJFrogAppsConfig(cmdResults.GetTargetsPaths()) if err != nil { return cmdResults, fmt.Errorf("failed to create JFrogAppsConfig: %s", err.Error()) } @@ -320,12 +320,10 @@ func detectScanTargets(cmdResults *results.SecurityCommandResults, params *Audit if len(workingDirs) == 0 { // Requested technology (from params) descriptors/indicators was not found, scan only requested directory for this technology. cmdResults.NewScanResults(results.ScanTarget{Target: requestedDirectory, Technology: tech}) - // scansToPreform = append(scansToPreform, &results.ScanTarget{Target: requestedDirectory, Technology: tech}) } for workingDir, descriptors := range workingDirs { // Add scan for each detected working directory. cmdResults.NewScanResults(results.ScanTarget{Target: workingDir, Technology: tech}).SetDescriptors(descriptors...) - // scansToPreform = append(scansToPreform, &results.ScanTarget{Target: workingDir, Technology: tech, Descriptors: descriptors}) } } } diff --git a/commands/audit/scarunner.go b/commands/audit/scarunner.go index 1ca553ca..c64241d4 100644 --- a/commands/audit/scarunner.go +++ b/commands/audit/scarunner.go @@ -95,39 +95,6 @@ func buildDepTreeAndRunScaScan(auditParallelRunner *utils.SecurityParallelRunner return } -// // Calculate the scans to preform -// func getScaScansToPreform(params *AuditParams) (scansToPreform []*results.ScanTarget) { -// for _, requestedDirectory := range params.workingDirs { -// if !fileutils.IsPathExists(requestedDirectory, false) { -// log.Warn("The working directory", requestedDirectory, "doesn't exist. Skipping SCA scan...") -// continue -// } -// // Detect descriptors and technologies in the requested directory. -// techToWorkingDirs, err := techutils.DetectTechnologiesDescriptors(requestedDirectory, params.IsRecursiveScan(), params.Technologies(), getRequestedDescriptors(params), sca.GetExcludePattern(params.AuditBasicParams)) -// if err != nil { -// log.Warn("Couldn't detect technologies in", requestedDirectory, "directory.", err.Error()) -// continue -// } -// // Create scans to preform -// for tech, workingDirs := range techToWorkingDirs { -// if tech == techutils.Dotnet { -// // We detect Dotnet and Nuget the same way, if one detected so does the other. -// // We don't need to scan for both and get duplicate results. -// continue -// } -// if len(workingDirs) == 0 { -// // Requested technology (from params) descriptors/indicators was not found, scan only requested directory for this technology. -// scansToPreform = append(scansToPreform, &results.ScanTarget{Target: requestedDirectory, Technology: tech}) -// } -// for workingDir, descriptors := range workingDirs { -// // Add scan for each detected working directory. -// scansToPreform = append(scansToPreform, &results.ScanTarget{Target: workingDir, Technology: tech, Descriptors: descriptors}) -// } -// } -// } -// return -// } - func getRequestedDescriptors(params *AuditParams) map[techutils.Technology][]string { requestedDescriptors := map[techutils.Technology][]string{} if params.PipRequirementsFile() != "" { diff --git a/jas/applicability/applicabilitymanager_test.go b/jas/applicability/applicabilitymanager_test.go index ab3fab24..117219a7 100644 --- a/jas/applicability/applicabilitymanager_test.go +++ b/jas/applicability/applicabilitymanager_test.go @@ -42,7 +42,6 @@ func TestNewApplicabilityScanManager_DependencyTreeDoesntExist(t *testing.T) { // Assert if assert.NotNil(t, applicabilityManager) { assert.NotNil(t, applicabilityManager.scanner.ScannerDirCleanupFunc) - // assert.Len(t, applicabilityManager.scanner.JFrogAppsConfig.Modules, 1) assert.NotEmpty(t, applicabilityManager.configFileName) assert.NotEmpty(t, applicabilityManager.resultsFileName) assert.Empty(t, applicabilityManager.directDependenciesCves) diff --git a/jas/common.go b/jas/common.go index fcbb4b94..025346ea 100644 --- a/jas/common.go +++ b/jas/common.go @@ -32,10 +32,9 @@ import ( ) type JasScanner struct { - TempDir string - AnalyzerManager AnalyzerManager - ServerDetails *config.ServerDetails - // JFrogAppsConfig *jfrogappsconfig.JFrogAppsConfig + TempDir string + AnalyzerManager AnalyzerManager + ServerDetails *config.ServerDetails ScannerDirCleanupFunc func() error EnvVars map[string]string Exclusions []string @@ -58,7 +57,6 @@ func CreateJasScanner(scanner *JasScanner, serverDetails *config.ServerDetails, return fileutils.RemoveTempDir(tempDir) } scanner.ServerDetails = serverDetails - // scanner.JFrogAppsConfig = jfrogAppsConfig scanner.Exclusions = exclusions return scanner, err } @@ -76,9 +74,9 @@ func CreateJFrogAppsConfig(workingDirs []string) (*jfrogappsconfig.JFrogAppsConf return nil, errorutils.CheckError(err) } else if jfrogAppsConfig != nil { // jfrog-apps-config.yml exist in the workspace - for _, module := range jfrogAppsConfig.Modules { + for i := range jfrogAppsConfig.Modules { // converting to absolute path before starting the scan flow - module.SourceRoot, err = filepath.Abs(module.SourceRoot) + jfrogAppsConfig.Modules[i].SourceRoot, err = filepath.Abs(jfrogAppsConfig.Modules[i].SourceRoot) if err != nil { return nil, errorutils.CheckError(err) } diff --git a/tests/testdata/other/output/formats/audit_results.json b/tests/testdata/other/output/formats/audit_results.json index ca11075d..1eee5a96 100644 --- a/tests/testdata/other/output/formats/audit_results.json +++ b/tests/testdata/other/output/formats/audit_results.json @@ -4,12 +4,12 @@ "multi_scan_id": "7d5e4733-3f93-11ef-8147-e610d09d7daa", "targets": [ { - "target": "/Users/user/ejs-frog-demo", + "target": "/users/user/ejs-frog-demo", "technology": "npm", "sca_scans": { "is_multiple_root_project": false, "descriptors": [ - "/Users/user/ejs-frog-demo/package.json" + "/users/user/ejs-frog-demo/package.json" ], "xray_scan": [ { @@ -964,7 +964,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" + "uri": "/users/user/ejs-frog-demo" } } ], @@ -978,7 +978,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1009,7 +1009,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1061,7 +1061,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1099,7 +1099,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 15, @@ -1123,7 +1123,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 27, @@ -1229,7 +1229,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" + "uri": "/users/user/ejs-frog-demo" } } ], @@ -1243,7 +1243,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:///users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 1, @@ -1267,7 +1267,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:///users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 2, @@ -1291,7 +1291,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:///users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 3, @@ -1315,7 +1315,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 10, @@ -1339,7 +1339,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 11, @@ -1376,7 +1376,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" + "uri": "/users/user/ejs-frog-demo" } } ], @@ -1457,7 +1457,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" + "uri": "/users/user/ejs-frog-demo" } } ], @@ -1472,7 +1472,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" + "uri": "file:///users/user/ejs-frog-demo/public/js/bootstrap.js" }, "region": { "startLine": 136, @@ -1502,7 +1502,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + "uri": "file:///users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" }, "region": { "startLine": 135, @@ -1532,7 +1532,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 8, @@ -1562,7 +1562,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -1590,7 +1590,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 22, @@ -1613,7 +1613,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 27, @@ -1636,7 +1636,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 27, diff --git a/tests/testdata/other/output/formats/audit_sarif.json b/tests/testdata/other/output/formats/audit_sarif.json index 87e119ee..d313921e 100644 --- a/tests/testdata/other/output/formats/audit_sarif.json +++ b/tests/testdata/other/output/formats/audit_sarif.json @@ -82,7 +82,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" + "uri": "/users/user/ejs-frog-demo" } } ], @@ -96,7 +96,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:///users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 1, @@ -120,7 +120,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:///users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 2, @@ -144,7 +144,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:///users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 3, @@ -168,7 +168,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 10, @@ -192,7 +192,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 11, @@ -227,7 +227,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" + "uri": "/users/user/ejs-frog-demo" } } ], @@ -306,7 +306,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" + "uri": "/users/user/ejs-frog-demo" } } ], @@ -321,7 +321,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" + "uri": "file:///users/user/ejs-frog-demo/public/js/bootstrap.js" }, "region": { "startLine": 136, @@ -351,7 +351,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + "uri": "file:///users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" }, "region": { "startLine": 135, @@ -381,7 +381,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 8, @@ -411,7 +411,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -439,7 +439,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 21, @@ -462,7 +462,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -485,7 +485,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "file:///users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -682,7 +682,7 @@ { "executionSuccessful": true, "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" + "uri": "/users/user/ejs-frog-demo" } } ], @@ -702,7 +702,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "file:///users/user/ejs-frog-demo/package.json" } } } @@ -723,7 +723,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "file:///users/user/ejs-frog-demo/package.json" } } } @@ -744,7 +744,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "file:///users/user/ejs-frog-demo/package.json" } } } @@ -765,7 +765,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "file:///users/user/ejs-frog-demo/package.json" } } } @@ -786,7 +786,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "file:///users/user/ejs-frog-demo/package.json" } } } @@ -807,7 +807,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "file:///users/user/ejs-frog-demo/package.json" } } } @@ -828,7 +828,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "file:///users/user/ejs-frog-demo/package.json" } } } @@ -849,7 +849,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "file:///users/user/ejs-frog-demo/package.json" } } } @@ -870,7 +870,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "file:///users/user/ejs-frog-demo/package.json" } } } @@ -891,7 +891,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "file:///users/user/ejs-frog-demo/package.json" } } } @@ -912,7 +912,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "file:///users/user/ejs-frog-demo/package.json" } } } @@ -933,7 +933,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "file:///users/user/ejs-frog-demo/package.json" } } } diff --git a/tests/testdata/other/output/formats/audit_simple_json.json b/tests/testdata/other/output/formats/audit_simple_json.json index 44a43ac1..dbde0ec9 100644 --- a/tests/testdata/other/output/formats/audit_simple_json.json +++ b/tests/testdata/other/output/formats/audit_simple_json.json @@ -10,7 +10,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/Users/user/ejs-frog-demo/package.json" + "file": "/users/user/ejs-frog-demo/package.json" } } ], @@ -88,7 +88,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/Users/user/ejs-frog-demo/package.json" + "file": "/users/user/ejs-frog-demo/package.json" } } ], @@ -133,7 +133,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/Users/user/ejs-frog-demo/package.json" + "file": "/users/user/ejs-frog-demo/package.json" } } ], @@ -178,7 +178,7 @@ "name": "express", "version": "4.18.2", "location": { - "file": "/Users/user/ejs-frog-demo/package.json" + "file": "/users/user/ejs-frog-demo/package.json" } } ], @@ -224,7 +224,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/Users/user/ejs-frog-demo/package.json" + "file": "/users/user/ejs-frog-demo/package.json" } } ], @@ -300,7 +300,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/Users/user/ejs-frog-demo/package.json" + "file": "/users/user/ejs-frog-demo/package.json" } } ], @@ -377,7 +377,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/Users/user/ejs-frog-demo/package.json" + "file": "/users/user/ejs-frog-demo/package.json" } } ], @@ -453,7 +453,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/Users/user/ejs-frog-demo/package.json" + "file": "/users/user/ejs-frog-demo/package.json" } } ], @@ -523,7 +523,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/Users/user/ejs-frog-demo/package.json" + "file": "/users/user/ejs-frog-demo/package.json" } } ], @@ -586,7 +586,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/Users/user/ejs-frog-demo/package.json" + "file": "/users/user/ejs-frog-demo/package.json" } } ], @@ -663,7 +663,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/Users/user/ejs-frog-demo/package.json" + "file": "/users/user/ejs-frog-demo/package.json" } } ], @@ -729,7 +729,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/Users/user/ejs-frog-demo/package.json" + "file": "/users/user/ejs-frog-demo/package.json" } } ], diff --git a/tests/testdata/other/output/formats/audit_summary.json b/tests/testdata/other/output/formats/audit_summary.json index d0da55a1..d8813d36 100644 --- a/tests/testdata/other/output/formats/audit_summary.json +++ b/tests/testdata/other/output/formats/audit_summary.json @@ -1,7 +1,7 @@ { "scans": [ { - "target": "/Users/user/ejs-frog-demo", + "target": "/users/user/ejs-frog-demo", "vulnerabilities": { "sca": { "sca": { diff --git a/tests/testdata/other/output/formats/audit_table.json b/tests/testdata/other/output/formats/audit_table.json deleted file mode 100644 index e69de29b..00000000 diff --git a/utils/formats/conversion.go b/utils/formats/conversion.go index a5e31068..52644095 100644 --- a/utils/formats/conversion.go +++ b/utils/formats/conversion.go @@ -101,24 +101,6 @@ func ConvertToVulnerabilityTableRow(rows []VulnerabilityOrViolationRow) (tableRo return } -// func ConvertToVulnerabilityScanTableRow(rows []VulnerabilityOrViolationRow) (tableRows []vulnerabilityScanTableRow) { -// for i := range rows { -// tableRows = append(tableRows, vulnerabilityScanTableRow{ -// severity: rows[i].Severity, -// severityNumValue: rows[i].SeverityNumValue, -// applicable: rows[i].Applicable, -// impactedPackageName: rows[i].ImpactedDependencyName, -// impactedPackageVersion: rows[i].ImpactedDependencyVersion, -// ImpactedPackageType: rows[i].ImpactedDependencyType, -// fixedVersions: strings.Join(rows[i].FixedVersions, "\n"), -// directPackages: convertToComponentScanTableRow(rows[i].Components), -// cves: convertToCveTableRow(rows[i].Cves), -// issueId: rows[i].IssueId, -// }) -// } -// return -// } - func ConvertToLicenseViolationTableRow(rows []LicenseRow) (tableRows []licenseViolationTableRow) { for i := range rows { tableRows = append(tableRows, licenseViolationTableRow{ @@ -134,21 +116,6 @@ func ConvertToLicenseViolationTableRow(rows []LicenseRow) (tableRows []licenseVi return } -// func ConvertToLicenseViolationScanTableRow(rows []LicenseRow) (tableRows []licenseViolationScanTableRow) { -// for i := range rows { -// tableRows = append(tableRows, licenseViolationScanTableRow{ -// licenseKey: rows[i].LicenseKey, -// severity: rows[i].Severity, -// severityNumValue: rows[i].SeverityNumValue, -// impactedPackageName: rows[i].ImpactedDependencyName, -// impactedPackageVersion: rows[i].ImpactedDependencyVersion, -// impactedDependencyType: rows[i].ImpactedDependencyType, -// directDependencies: convertToComponentScanTableRow(rows[i].Components), -// }) -// } -// return -// } - func ConvertToLicenseTableRow(rows []LicenseRow) (tableRows []licenseTableRow) { for i := range rows { tableRows = append(tableRows, licenseTableRow{ @@ -162,19 +129,6 @@ func ConvertToLicenseTableRow(rows []LicenseRow) (tableRows []licenseTableRow) { return } -// func ConvertToLicenseScanTableRow(rows []LicenseRow) (tableRows []licenseScanTableRow) { -// for i := range rows { -// tableRows = append(tableRows, licenseScanTableRow{ -// licenseKey: rows[i].LicenseKey, -// impactedPackageName: rows[i].ImpactedDependencyName, -// impactedPackageVersion: rows[i].ImpactedDependencyVersion, -// impactedDependencyType: rows[i].ImpactedDependencyType, -// directDependencies: convertToComponentScanTableRow(rows[i].Components), -// }) -// } -// return -// } - func ConvertToOperationalRiskViolationTableRow(rows []OperationalRiskViolationRow) (tableRows []operationalRiskViolationTableRow) { for i := range rows { tableRows = append(tableRows, operationalRiskViolationTableRow{ @@ -197,28 +151,6 @@ func ConvertToOperationalRiskViolationTableRow(rows []OperationalRiskViolationRo return } -// func ConvertToOperationalRiskViolationScanTableRow(rows []OperationalRiskViolationRow) (tableRows []operationalRiskViolationScanTableRow) { -// for i := range rows { -// tableRows = append(tableRows, operationalRiskViolationScanTableRow{ -// Severity: rows[i].Severity, -// severityNumValue: rows[i].SeverityNumValue, -// impactedPackageName: rows[i].ImpactedDependencyName, -// impactedPackageVersion: rows[i].ImpactedDependencyVersion, -// impactedDependencyType: rows[i].ImpactedDependencyType, -// directDependencies: convertToComponentScanTableRow(rows[i].Components), -// isEol: rows[i].IsEol, -// cadence: rows[i].Cadence, -// commits: rows[i].Commits, -// committers: rows[i].Committers, -// newerVersions: rows[i].NewerVersions, -// latestVersion: rows[i].LatestVersion, -// riskReason: rows[i].RiskReason, -// eolMessage: rows[i].EolMessage, -// }) -// } -// return -// } - func ConvertToSecretsTableRow(rows []SourceCodeRow) (tableRows []secretsTableRow) { for i := range rows { tableRows = append(tableRows, secretsTableRow{ @@ -253,16 +185,6 @@ func convertToComponentTableRow(rows []ComponentRow) (tableRows []directDependen return } -// func convertToComponentScanTableRow(rows []ComponentRow) (tableRows []directPackagesTableRow) { -// for i := range rows { -// tableRows = append(tableRows, directPackagesTableRow{ -// name: rows[i].Name, -// version: rows[i].Version, -// }) -// } -// return -// } - func convertToCveTableRow(rows []CveRow) (tableRows []cveTableRow) { for i := range rows { tableRows = append(tableRows, cveTableRow{ diff --git a/utils/results/common_test.go b/utils/results/common_test.go index ce4d979e..4dca1930 100644 --- a/utils/results/common_test.go +++ b/utils/results/common_test.go @@ -77,13 +77,6 @@ func TestFindMaxCVEScore(t *testing.T) { } func TestGetIssueIdentifier(t *testing.T) { - // issueId := "XRAY-123456" - // cvesRow := []formats.CveRow{{Id: "CVE-2022-1234"}} - // assert.Equal(t, "CVE-2022-1234", GetIssueIdentifier(cvesRow, issueId)) - // cvesRow = append(cvesRow, formats.CveRow{Id: "CVE-2019-1234"}) - // assert.Equal(t, "CVE-2022-1234, CVE-2019-1234", GetIssueIdentifier(cvesRow, issueId)) - // assert.Equal(t, issueId, GetIssueIdentifier(nil, issueId)) - testCases := []struct { name string cves []formats.CveRow @@ -366,60 +359,6 @@ func TestAppendUniqueImpactPaths(t *testing.T) { } } -// func TestGetXrayIssueLocationIfValidExists(t *testing.T) { -// testDir, cleanup := tests.CreateTempDirWithCallbackAndAssert(t) -// defer cleanup() -// invocation := sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(testDir)) -// file, err := os.Create(filepath.Join(testDir, "go.mod")) -// assert.NoError(t, err) -// assert.NotNil(t, file) -// defer func() { assert.NoError(t, file.Close()) }() -// file2, err := os.Create(filepath.Join(testDir, "build.gradle.kts")) -// assert.NoError(t, err) -// assert.NotNil(t, file2) -// defer func() { assert.NoError(t, file2.Close()) }() - -// testCases := []struct { -// name string -// tech techutils.Technology -// run *sarif.Run -// expectedOutput *sarif.Location -// }{ -// { -// name: "No descriptor information", -// tech: techutils.Pip, -// run: sarifutils.CreateRunWithDummyResults().WithInvocations([]*sarif.Invocation{invocation}), -// expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://Package-Descriptor"))), -// }, -// { -// name: "One descriptor information", -// tech: techutils.Go, -// run: sarifutils.CreateRunWithDummyResults().WithInvocations([]*sarif.Invocation{invocation}), -// expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://" + filepath.Join(testDir, "go.mod")))), -// }, -// { -// name: "One descriptor information - no invocation", -// tech: techutils.Go, -// run: sarifutils.CreateRunWithDummyResults(), -// expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://go.mod"))), -// }, -// { -// name: "Multiple descriptor information", -// tech: techutils.Gradle, -// run: sarifutils.CreateRunWithDummyResults().WithInvocations([]*sarif.Invocation{invocation}), -// expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://" + filepath.Join(testDir, "build.gradle.kts")))), -// }, -// } -// for _, tc := range testCases { -// t.Run(tc.name, func(t *testing.T) { -// output, err := getXrayIssueLocationIfValidExists(tc.tech, tc.run) -// if assert.NoError(t, err) { -// assert.Equal(t, tc.expectedOutput, output) -// } -// }) -// } -// } - func TestGetApplicableCveValue(t *testing.T) { testCases := []struct { name string diff --git a/utils/results/results.go b/utils/results/results.go index 15c790b3..ca9e6552 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -72,6 +72,13 @@ func (r *SecurityCommandResults) SetMultiScanId(multiScanId string) *SecurityCom // --- Aggregated results for all targets --- +func (r *SecurityCommandResults) GetTargetsPaths() (paths []string) { + for _, scan := range r.Targets { + paths = append(paths, scan.Target) + } + return +} + func (r *SecurityCommandResults) GetScaScansXrayResults() (results []services.ScanResponse) { for _, scan := range r.Targets { results = append(results, scan.GetScaScansXrayResults()...) From f201811461febb4792039a1aee4e447209743387 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 23 Jul 2024 15:38:56 +0300 Subject: [PATCH 37/82] fix win test and cleanup --- .../other/output/formats/audit_results.json | 46 ++-- .../other/output/formats/audit_sarif.json | 56 ++--- .../output/formats/audit_simple_json.json | 24 +-- .../other/output/formats/audit_summary.json | 2 +- tests/utils/test_utils.go | 3 +- .../summaryparser/summaryparser_test.go | 123 ----------- .../results/output/securityJobSummary_test.go | 6 - utils/results/results.go | 12 -- utils/results/results_test.go | 203 ------------------ .../validations/test_validate_simple_json.go | 28 --- utils/validations/test_validation.go | 57 ----- 11 files changed, 66 insertions(+), 494 deletions(-) delete mode 100644 utils/results/results_test.go diff --git a/tests/testdata/other/output/formats/audit_results.json b/tests/testdata/other/output/formats/audit_results.json index 1eee5a96..b31ff4ef 100644 --- a/tests/testdata/other/output/formats/audit_results.json +++ b/tests/testdata/other/output/formats/audit_results.json @@ -4,12 +4,12 @@ "multi_scan_id": "7d5e4733-3f93-11ef-8147-e610d09d7daa", "targets": [ { - "target": "/users/user/ejs-frog-demo", + "target": "Users/user/ejs-frog-demo", "technology": "npm", "sca_scans": { "is_multiple_root_project": false, "descriptors": [ - "/users/user/ejs-frog-demo/package.json" + "Users/user/ejs-frog-demo/package.json" ], "xray_scan": [ { @@ -964,7 +964,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/users/user/ejs-frog-demo" + "uri": "Users/user/ejs-frog-demo" } } ], @@ -978,7 +978,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1009,7 +1009,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1061,7 +1061,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1099,7 +1099,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 15, @@ -1123,7 +1123,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 27, @@ -1229,7 +1229,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/users/user/ejs-frog-demo" + "uri": "Users/user/ejs-frog-demo" } } ], @@ -1243,7 +1243,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file://Users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 1, @@ -1267,7 +1267,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file://Users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 2, @@ -1291,7 +1291,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file://Users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 3, @@ -1315,7 +1315,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 10, @@ -1339,7 +1339,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 11, @@ -1376,7 +1376,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/users/user/ejs-frog-demo" + "uri": "Users/user/ejs-frog-demo" } } ], @@ -1457,7 +1457,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/users/user/ejs-frog-demo" + "uri": "Users/user/ejs-frog-demo" } } ], @@ -1472,7 +1472,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/public/js/bootstrap.js" + "uri": "file://Users/user/ejs-frog-demo/public/js/bootstrap.js" }, "region": { "startLine": 136, @@ -1502,7 +1502,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + "uri": "file://Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" }, "region": { "startLine": 135, @@ -1532,7 +1532,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 8, @@ -1562,7 +1562,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -1590,7 +1590,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 22, @@ -1613,7 +1613,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 27, @@ -1636,7 +1636,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 27, diff --git a/tests/testdata/other/output/formats/audit_sarif.json b/tests/testdata/other/output/formats/audit_sarif.json index d313921e..a17895a4 100644 --- a/tests/testdata/other/output/formats/audit_sarif.json +++ b/tests/testdata/other/output/formats/audit_sarif.json @@ -82,7 +82,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/users/user/ejs-frog-demo" + "uri": "Users/user/ejs-frog-demo" } } ], @@ -96,7 +96,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file://Users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 1, @@ -120,7 +120,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file://Users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 2, @@ -144,7 +144,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file://Users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 3, @@ -168,7 +168,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 10, @@ -192,7 +192,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 11, @@ -227,7 +227,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/users/user/ejs-frog-demo" + "uri": "Users/user/ejs-frog-demo" } } ], @@ -306,7 +306,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/users/user/ejs-frog-demo" + "uri": "Users/user/ejs-frog-demo" } } ], @@ -321,7 +321,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/public/js/bootstrap.js" + "uri": "file://Users/user/ejs-frog-demo/public/js/bootstrap.js" }, "region": { "startLine": 136, @@ -351,7 +351,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + "uri": "file://Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" }, "region": { "startLine": 135, @@ -381,7 +381,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 8, @@ -411,7 +411,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -439,7 +439,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 21, @@ -462,7 +462,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -485,7 +485,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/server.js" + "uri": "file://Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -682,7 +682,7 @@ { "executionSuccessful": true, "workingDirectory": { - "uri": "/users/user/ejs-frog-demo" + "uri": "Users/user/ejs-frog-demo" } } ], @@ -702,7 +702,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/package.json" + "uri": "file://Users/user/ejs-frog-demo/package.json" } } } @@ -723,7 +723,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/package.json" + "uri": "file://Users/user/ejs-frog-demo/package.json" } } } @@ -744,7 +744,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/package.json" + "uri": "file://Users/user/ejs-frog-demo/package.json" } } } @@ -765,7 +765,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/package.json" + "uri": "file://Users/user/ejs-frog-demo/package.json" } } } @@ -786,7 +786,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/package.json" + "uri": "file://Users/user/ejs-frog-demo/package.json" } } } @@ -807,7 +807,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/package.json" + "uri": "file://Users/user/ejs-frog-demo/package.json" } } } @@ -828,7 +828,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/package.json" + "uri": "file://Users/user/ejs-frog-demo/package.json" } } } @@ -849,7 +849,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/package.json" + "uri": "file://Users/user/ejs-frog-demo/package.json" } } } @@ -870,7 +870,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/package.json" + "uri": "file://Users/user/ejs-frog-demo/package.json" } } } @@ -891,7 +891,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/package.json" + "uri": "file://Users/user/ejs-frog-demo/package.json" } } } @@ -912,7 +912,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/package.json" + "uri": "file://Users/user/ejs-frog-demo/package.json" } } } @@ -933,7 +933,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///users/user/ejs-frog-demo/package.json" + "uri": "file://Users/user/ejs-frog-demo/package.json" } } } diff --git a/tests/testdata/other/output/formats/audit_simple_json.json b/tests/testdata/other/output/formats/audit_simple_json.json index dbde0ec9..407f0058 100644 --- a/tests/testdata/other/output/formats/audit_simple_json.json +++ b/tests/testdata/other/output/formats/audit_simple_json.json @@ -10,7 +10,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/users/user/ejs-frog-demo/package.json" + "file": "Users/user/ejs-frog-demo/package.json" } } ], @@ -88,7 +88,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/users/user/ejs-frog-demo/package.json" + "file": "Users/user/ejs-frog-demo/package.json" } } ], @@ -133,7 +133,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/users/user/ejs-frog-demo/package.json" + "file": "Users/user/ejs-frog-demo/package.json" } } ], @@ -178,7 +178,7 @@ "name": "express", "version": "4.18.2", "location": { - "file": "/users/user/ejs-frog-demo/package.json" + "file": "Users/user/ejs-frog-demo/package.json" } } ], @@ -224,7 +224,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/users/user/ejs-frog-demo/package.json" + "file": "Users/user/ejs-frog-demo/package.json" } } ], @@ -300,7 +300,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/users/user/ejs-frog-demo/package.json" + "file": "Users/user/ejs-frog-demo/package.json" } } ], @@ -377,7 +377,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/users/user/ejs-frog-demo/package.json" + "file": "Users/user/ejs-frog-demo/package.json" } } ], @@ -453,7 +453,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/users/user/ejs-frog-demo/package.json" + "file": "Users/user/ejs-frog-demo/package.json" } } ], @@ -523,7 +523,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/users/user/ejs-frog-demo/package.json" + "file": "Users/user/ejs-frog-demo/package.json" } } ], @@ -586,7 +586,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/users/user/ejs-frog-demo/package.json" + "file": "Users/user/ejs-frog-demo/package.json" } } ], @@ -663,7 +663,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/users/user/ejs-frog-demo/package.json" + "file": "Users/user/ejs-frog-demo/package.json" } } ], @@ -729,7 +729,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/users/user/ejs-frog-demo/package.json" + "file": "Users/user/ejs-frog-demo/package.json" } } ], diff --git a/tests/testdata/other/output/formats/audit_summary.json b/tests/testdata/other/output/formats/audit_summary.json index d8813d36..b1cff79f 100644 --- a/tests/testdata/other/output/formats/audit_summary.json +++ b/tests/testdata/other/output/formats/audit_summary.json @@ -1,7 +1,7 @@ { "scans": [ { - "target": "/users/user/ejs-frog-demo", + "target": "Users/user/ejs-frog-demo", "vulnerabilities": { "sca": { "sca": { diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index 2f56c2a5..4cab9118 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -136,8 +136,9 @@ func ChangeWD(t *testing.T, newPath string) string { func ReadOutputFromFile(t *testing.T, path string) string { content, err := os.ReadFile(path) + assert.NoError(t, err) - return strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(string(content), "\r\n", "\n"), "/", string(filepath.Separator)), "<"+string(filepath.Separator), " Date: Tue, 23 Jul 2024 16:20:46 +0300 Subject: [PATCH 38/82] fix tests --- .../other/output/formats/audit_results.json | 64 ++++++++--------- .../other/output/formats/audit_sarif.json | 70 +++++++++---------- .../output/formats/audit_simple_json.json | 24 +++---- .../other/output/formats/audit_summary.json | 2 +- 4 files changed, 80 insertions(+), 80 deletions(-) diff --git a/tests/testdata/other/output/formats/audit_results.json b/tests/testdata/other/output/formats/audit_results.json index b31ff4ef..d0a99d80 100644 --- a/tests/testdata/other/output/formats/audit_results.json +++ b/tests/testdata/other/output/formats/audit_results.json @@ -4,12 +4,12 @@ "multi_scan_id": "7d5e4733-3f93-11ef-8147-e610d09d7daa", "targets": [ { - "target": "Users/user/ejs-frog-demo", + "target": "user/ejs-frog-demo", "technology": "npm", "sca_scans": { "is_multiple_root_project": false, "descriptors": [ - "Users/user/ejs-frog-demo/package.json" + "user/ejs-frog-demo/package.json" ], "xray_scan": [ { @@ -958,13 +958,13 @@ "invocations": [ { "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "analyzerManager/jas_scanner/jas_scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720701347-1703878693/Applicability_1720701359/config.yaml" + "Applicability/config.yaml" ], "executionSuccessful": true, "workingDirectory": { - "uri": "Users/user/ejs-frog-demo" + "uri": "user/ejs-frog-demo" } } ], @@ -978,7 +978,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1009,7 +1009,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1061,7 +1061,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1099,7 +1099,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 15, @@ -1123,7 +1123,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 27, @@ -1223,13 +1223,13 @@ "invocations": [ { "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "analyzerManager/jas_scanner/jas_scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720701347-1703878693/Secrets_1720701347/config.yaml" + "Secrets/config.yaml" ], "executionSuccessful": true, "workingDirectory": { - "uri": "Users/user/ejs-frog-demo" + "uri": "user/ejs-frog-demo" } } ], @@ -1243,7 +1243,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 1, @@ -1267,7 +1267,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 2, @@ -1291,7 +1291,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 3, @@ -1315,7 +1315,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 10, @@ -1339,7 +1339,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 11, @@ -1370,13 +1370,13 @@ "invocations": [ { "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/iac_scanner/tf_scanner", + "analyzerManager/iac_scanner/tf_scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720701347-1703878693/IaC_1720701359/config.yaml" + "IaC/config.yaml" ], "executionSuccessful": true, "workingDirectory": { - "uri": "Users/user/ejs-frog-demo" + "uri": "user/ejs-frog-demo" } } ], @@ -1450,14 +1450,14 @@ "invocations": [ { "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", + "analyzerManager/zd_scanner/scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720701347-1703878693/Sast_1720701360/results.sarif", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1720701347-1703878693/Sast_1720701360/config.yaml" + "Sast/results.sarif", + "Sast/config.yaml" ], "executionSuccessful": true, "workingDirectory": { - "uri": "Users/user/ejs-frog-demo" + "uri": "user/ejs-frog-demo" } } ], @@ -1472,7 +1472,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/public/js/bootstrap.js" + "uri": "file:/user/ejs-frog-demo/public/js/bootstrap.js" }, "region": { "startLine": 136, @@ -1502,7 +1502,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + "uri": "file:/user/ejs-frog-demo/public/js/bootstrap.bundle.js" }, "region": { "startLine": 135, @@ -1532,7 +1532,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 8, @@ -1562,7 +1562,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -1590,7 +1590,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 22, @@ -1613,7 +1613,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 27, @@ -1636,7 +1636,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 27, diff --git a/tests/testdata/other/output/formats/audit_sarif.json b/tests/testdata/other/output/formats/audit_sarif.json index a17895a4..41b7497e 100644 --- a/tests/testdata/other/output/formats/audit_sarif.json +++ b/tests/testdata/other/output/formats/audit_sarif.json @@ -76,13 +76,13 @@ "invocations": [ { "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "analyzerManager/jas_scanner/jas_scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721657068-1669763637/Secrets_1721657068/config.yaml" + "Secrets/config.yaml" ], "executionSuccessful": true, "workingDirectory": { - "uri": "Users/user/ejs-frog-demo" + "uri": "user/ejs-frog-demo" } } ], @@ -96,7 +96,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 1, @@ -120,7 +120,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 2, @@ -144,7 +144,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 3, @@ -168,7 +168,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 10, @@ -192,7 +192,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 11, @@ -221,13 +221,13 @@ "invocations": [ { "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/iac_scanner/tf_scanner", + "analyzerManager/iac_scanner/tf_scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721657068-1669763637/IaC_1721657081/config.yaml" + "/IaC/config.yaml" ], "executionSuccessful": true, "workingDirectory": { - "uri": "Users/user/ejs-frog-demo" + "uri": "user/ejs-frog-demo" } } ], @@ -299,14 +299,14 @@ "invocations": [ { "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", + "analyzerManager/zd_scanner/scanner", "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721657068-1669763637/Sast_1721657083/results.sarif", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1721657068-1669763637/Sast_1721657083/config.yaml" + "Sast/results.sarif", + "Sast/config.yaml" ], "executionSuccessful": true, "workingDirectory": { - "uri": "Users/user/ejs-frog-demo" + "uri": "user/ejs-frog-demo" } } ], @@ -321,7 +321,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/public/js/bootstrap.js" + "uri": "file:/user/ejs-frog-demo/public/js/bootstrap.js" }, "region": { "startLine": 136, @@ -351,7 +351,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + "uri": "file:/user/ejs-frog-demo/public/js/bootstrap.bundle.js" }, "region": { "startLine": 135, @@ -381,7 +381,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 8, @@ -411,7 +411,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -439,7 +439,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 21, @@ -462,7 +462,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -485,7 +485,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/server.js" + "uri": "file:/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -682,7 +682,7 @@ { "executionSuccessful": true, "workingDirectory": { - "uri": "Users/user/ejs-frog-demo" + "uri": "user/ejs-frog-demo" } } ], @@ -702,7 +702,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/package.json" + "uri": "file:/user/ejs-frog-demo/package.json" } } } @@ -723,7 +723,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/package.json" + "uri": "file:/user/ejs-frog-demo/package.json" } } } @@ -744,7 +744,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/package.json" + "uri": "file:/user/ejs-frog-demo/package.json" } } } @@ -765,7 +765,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/package.json" + "uri": "file:/user/ejs-frog-demo/package.json" } } } @@ -786,7 +786,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/package.json" + "uri": "file:/user/ejs-frog-demo/package.json" } } } @@ -807,7 +807,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/package.json" + "uri": "file:/user/ejs-frog-demo/package.json" } } } @@ -828,7 +828,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/package.json" + "uri": "file:/user/ejs-frog-demo/package.json" } } } @@ -849,7 +849,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/package.json" + "uri": "file:/user/ejs-frog-demo/package.json" } } } @@ -870,7 +870,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/package.json" + "uri": "file:/user/ejs-frog-demo/package.json" } } } @@ -891,7 +891,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/package.json" + "uri": "file:/user/ejs-frog-demo/package.json" } } } @@ -912,7 +912,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/package.json" + "uri": "file:/user/ejs-frog-demo/package.json" } } } @@ -933,7 +933,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://Users/user/ejs-frog-demo/package.json" + "uri": "file:/user/ejs-frog-demo/package.json" } } } diff --git a/tests/testdata/other/output/formats/audit_simple_json.json b/tests/testdata/other/output/formats/audit_simple_json.json index 407f0058..8c7bb0ea 100644 --- a/tests/testdata/other/output/formats/audit_simple_json.json +++ b/tests/testdata/other/output/formats/audit_simple_json.json @@ -10,7 +10,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "Users/user/ejs-frog-demo/package.json" + "file": "user/ejs-frog-demo/package.json" } } ], @@ -88,7 +88,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "Users/user/ejs-frog-demo/package.json" + "file": "user/ejs-frog-demo/package.json" } } ], @@ -133,7 +133,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "Users/user/ejs-frog-demo/package.json" + "file": "user/ejs-frog-demo/package.json" } } ], @@ -178,7 +178,7 @@ "name": "express", "version": "4.18.2", "location": { - "file": "Users/user/ejs-frog-demo/package.json" + "file": "user/ejs-frog-demo/package.json" } } ], @@ -224,7 +224,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "Users/user/ejs-frog-demo/package.json" + "file": "user/ejs-frog-demo/package.json" } } ], @@ -300,7 +300,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "Users/user/ejs-frog-demo/package.json" + "file": "user/ejs-frog-demo/package.json" } } ], @@ -377,7 +377,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "Users/user/ejs-frog-demo/package.json" + "file": "user/ejs-frog-demo/package.json" } } ], @@ -453,7 +453,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "Users/user/ejs-frog-demo/package.json" + "file": "user/ejs-frog-demo/package.json" } } ], @@ -523,7 +523,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "Users/user/ejs-frog-demo/package.json" + "file": "user/ejs-frog-demo/package.json" } } ], @@ -586,7 +586,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "Users/user/ejs-frog-demo/package.json" + "file": "user/ejs-frog-demo/package.json" } } ], @@ -663,7 +663,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "Users/user/ejs-frog-demo/package.json" + "file": "user/ejs-frog-demo/package.json" } } ], @@ -729,7 +729,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "Users/user/ejs-frog-demo/package.json" + "file": "user/ejs-frog-demo/package.json" } } ], diff --git a/tests/testdata/other/output/formats/audit_summary.json b/tests/testdata/other/output/formats/audit_summary.json index b1cff79f..9c2adf3e 100644 --- a/tests/testdata/other/output/formats/audit_summary.json +++ b/tests/testdata/other/output/formats/audit_summary.json @@ -1,7 +1,7 @@ { "scans": [ { - "target": "Users/user/ejs-frog-demo", + "target": "user/ejs-frog-demo", "vulnerabilities": { "sca": { "sca": { From 4ee4bc6bf3317ebcef25ead59f6d3eb38891b32f Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 23 Jul 2024 17:01:01 +0300 Subject: [PATCH 39/82] fix tests --- .../other/output/formats/audit_results.json | 46 +++++++-------- .../other/output/formats/audit_sarif.json | 56 +++++++++---------- .../output/formats/audit_simple_json.json | 24 ++++---- .../other/output/formats/audit_summary.json | 2 +- 4 files changed, 64 insertions(+), 64 deletions(-) diff --git a/tests/testdata/other/output/formats/audit_results.json b/tests/testdata/other/output/formats/audit_results.json index d0a99d80..b0fc797a 100644 --- a/tests/testdata/other/output/formats/audit_results.json +++ b/tests/testdata/other/output/formats/audit_results.json @@ -4,12 +4,12 @@ "multi_scan_id": "7d5e4733-3f93-11ef-8147-e610d09d7daa", "targets": [ { - "target": "user/ejs-frog-demo", + "target": "/dir/ejs-frog-demo", "technology": "npm", "sca_scans": { "is_multiple_root_project": false, "descriptors": [ - "user/ejs-frog-demo/package.json" + "/dir/ejs-frog-demo/package.json" ], "xray_scan": [ { @@ -964,7 +964,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "user/ejs-frog-demo" + "uri": "/dir/ejs-frog-demo" } } ], @@ -978,7 +978,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1009,7 +1009,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1061,7 +1061,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1099,7 +1099,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 15, @@ -1123,7 +1123,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 27, @@ -1229,7 +1229,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "user/ejs-frog-demo" + "uri": "/dir/ejs-frog-demo" } } ], @@ -1243,7 +1243,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:///dir/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 1, @@ -1267,7 +1267,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:///dir/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 2, @@ -1291,7 +1291,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:///dir/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 3, @@ -1315,7 +1315,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 10, @@ -1339,7 +1339,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 11, @@ -1376,7 +1376,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "user/ejs-frog-demo" + "uri": "/dir/ejs-frog-demo" } } ], @@ -1457,7 +1457,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "user/ejs-frog-demo" + "uri": "/dir/ejs-frog-demo" } } ], @@ -1472,7 +1472,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/public/js/bootstrap.js" + "uri": "file:///dir/ejs-frog-demo/public/js/bootstrap.js" }, "region": { "startLine": 136, @@ -1502,7 +1502,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + "uri": "file:///dir/ejs-frog-demo/public/js/bootstrap.bundle.js" }, "region": { "startLine": 135, @@ -1532,7 +1532,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 8, @@ -1562,7 +1562,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -1590,7 +1590,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 22, @@ -1613,7 +1613,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 27, @@ -1636,7 +1636,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 27, diff --git a/tests/testdata/other/output/formats/audit_sarif.json b/tests/testdata/other/output/formats/audit_sarif.json index 41b7497e..37aa8fd4 100644 --- a/tests/testdata/other/output/formats/audit_sarif.json +++ b/tests/testdata/other/output/formats/audit_sarif.json @@ -82,7 +82,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "user/ejs-frog-demo" + "uri": "/dir/ejs-frog-demo" } } ], @@ -96,7 +96,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:///dir/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 1, @@ -120,7 +120,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:///dir/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 2, @@ -144,7 +144,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/fake-creds.txt" + "uri": "file:///dir/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 3, @@ -168,7 +168,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 10, @@ -192,7 +192,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 11, @@ -227,7 +227,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "user/ejs-frog-demo" + "uri": "/dir/ejs-frog-demo" } } ], @@ -306,7 +306,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "user/ejs-frog-demo" + "uri": "/dir/ejs-frog-demo" } } ], @@ -321,7 +321,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/public/js/bootstrap.js" + "uri": "file:///dir/ejs-frog-demo/public/js/bootstrap.js" }, "region": { "startLine": 136, @@ -351,7 +351,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + "uri": "file:///dir/ejs-frog-demo/public/js/bootstrap.bundle.js" }, "region": { "startLine": 135, @@ -381,7 +381,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 8, @@ -411,7 +411,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -439,7 +439,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 21, @@ -462,7 +462,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -485,7 +485,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/server.js" + "uri": "file:///dir/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -682,7 +682,7 @@ { "executionSuccessful": true, "workingDirectory": { - "uri": "user/ejs-frog-demo" + "uri": "/dir/ejs-frog-demo" } } ], @@ -702,7 +702,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/package.json" + "uri": "file:///dir/ejs-frog-demo/package.json" } } } @@ -723,7 +723,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/package.json" + "uri": "file:///dir/ejs-frog-demo/package.json" } } } @@ -744,7 +744,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/package.json" + "uri": "file:///dir/ejs-frog-demo/package.json" } } } @@ -765,7 +765,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/package.json" + "uri": "file:///dir/ejs-frog-demo/package.json" } } } @@ -786,7 +786,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/package.json" + "uri": "file:///dir/ejs-frog-demo/package.json" } } } @@ -807,7 +807,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/package.json" + "uri": "file:///dir/ejs-frog-demo/package.json" } } } @@ -828,7 +828,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/package.json" + "uri": "file:///dir/ejs-frog-demo/package.json" } } } @@ -849,7 +849,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/package.json" + "uri": "file:///dir/ejs-frog-demo/package.json" } } } @@ -870,7 +870,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/package.json" + "uri": "file:///dir/ejs-frog-demo/package.json" } } } @@ -891,7 +891,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/package.json" + "uri": "file:///dir/ejs-frog-demo/package.json" } } } @@ -912,7 +912,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/package.json" + "uri": "file:///dir/ejs-frog-demo/package.json" } } } @@ -933,7 +933,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:/user/ejs-frog-demo/package.json" + "uri": "file:///dir/ejs-frog-demo/package.json" } } } diff --git a/tests/testdata/other/output/formats/audit_simple_json.json b/tests/testdata/other/output/formats/audit_simple_json.json index 8c7bb0ea..60d846ff 100644 --- a/tests/testdata/other/output/formats/audit_simple_json.json +++ b/tests/testdata/other/output/formats/audit_simple_json.json @@ -10,7 +10,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "user/ejs-frog-demo/package.json" + "file": "/dir/ejs-frog-demo/package.json" } } ], @@ -88,7 +88,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "user/ejs-frog-demo/package.json" + "file": "/dir/ejs-frog-demo/package.json" } } ], @@ -133,7 +133,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "user/ejs-frog-demo/package.json" + "file": "/dir/ejs-frog-demo/package.json" } } ], @@ -178,7 +178,7 @@ "name": "express", "version": "4.18.2", "location": { - "file": "user/ejs-frog-demo/package.json" + "file": "/dir/ejs-frog-demo/package.json" } } ], @@ -224,7 +224,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "user/ejs-frog-demo/package.json" + "file": "/dir/ejs-frog-demo/package.json" } } ], @@ -300,7 +300,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "user/ejs-frog-demo/package.json" + "file": "/dir/ejs-frog-demo/package.json" } } ], @@ -377,7 +377,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "user/ejs-frog-demo/package.json" + "file": "/dir/ejs-frog-demo/package.json" } } ], @@ -453,7 +453,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "user/ejs-frog-demo/package.json" + "file": "/dir/ejs-frog-demo/package.json" } } ], @@ -523,7 +523,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "user/ejs-frog-demo/package.json" + "file": "/dir/ejs-frog-demo/package.json" } } ], @@ -586,7 +586,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "user/ejs-frog-demo/package.json" + "file": "/dir/ejs-frog-demo/package.json" } } ], @@ -663,7 +663,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "user/ejs-frog-demo/package.json" + "file": "/dir/ejs-frog-demo/package.json" } } ], @@ -729,7 +729,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "user/ejs-frog-demo/package.json" + "file": "/dir/ejs-frog-demo/package.json" } } ], diff --git a/tests/testdata/other/output/formats/audit_summary.json b/tests/testdata/other/output/formats/audit_summary.json index 9c2adf3e..48904443 100644 --- a/tests/testdata/other/output/formats/audit_summary.json +++ b/tests/testdata/other/output/formats/audit_summary.json @@ -1,7 +1,7 @@ { "scans": [ { - "target": "user/ejs-frog-demo", + "target": "/dir/ejs-frog-demo", "vulnerabilities": { "sca": { "sca": { From 88ae5e5d8436c23fe20f4bba8051a61959f536dd Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 23 Jul 2024 17:32:05 +0300 Subject: [PATCH 40/82] try fix win tests --- .../other/output/formats/audit_results.json | 46 +++++++-------- .../other/output/formats/audit_sarif.json | 56 +++++++++---------- .../output/formats/audit_simple_json.json | 24 ++++---- .../other/output/formats/audit_summary.json | 2 +- tests/utils/test_utils.go | 1 - 5 files changed, 64 insertions(+), 65 deletions(-) diff --git a/tests/testdata/other/output/formats/audit_results.json b/tests/testdata/other/output/formats/audit_results.json index b0fc797a..deb8540a 100644 --- a/tests/testdata/other/output/formats/audit_results.json +++ b/tests/testdata/other/output/formats/audit_results.json @@ -4,12 +4,12 @@ "multi_scan_id": "7d5e4733-3f93-11ef-8147-e610d09d7daa", "targets": [ { - "target": "/dir/ejs-frog-demo", + "target": "ejs-frog-demo", "technology": "npm", "sca_scans": { "is_multiple_root_project": false, "descriptors": [ - "/dir/ejs-frog-demo/package.json" + "ejs-frog-demo/package.json" ], "xray_scan": [ { @@ -964,7 +964,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/dir/ejs-frog-demo" + "uri": "ejs-frog-demo" } } ], @@ -978,7 +978,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1009,7 +1009,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1061,7 +1061,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1099,7 +1099,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 15, @@ -1123,7 +1123,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 27, @@ -1229,7 +1229,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/dir/ejs-frog-demo" + "uri": "ejs-frog-demo" } } ], @@ -1243,7 +1243,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/fake-creds.txt" + "uri": "file://ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 1, @@ -1267,7 +1267,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/fake-creds.txt" + "uri": "file://ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 2, @@ -1291,7 +1291,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/fake-creds.txt" + "uri": "file://ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 3, @@ -1315,7 +1315,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 10, @@ -1339,7 +1339,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 11, @@ -1376,7 +1376,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/dir/ejs-frog-demo" + "uri": "ejs-frog-demo" } } ], @@ -1457,7 +1457,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/dir/ejs-frog-demo" + "uri": "ejs-frog-demo" } } ], @@ -1472,7 +1472,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/public/js/bootstrap.js" + "uri": "file://ejs-frog-demo/public/js/bootstrap.js" }, "region": { "startLine": 136, @@ -1502,7 +1502,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/public/js/bootstrap.bundle.js" + "uri": "file://ejs-frog-demo/public/js/bootstrap.bundle.js" }, "region": { "startLine": 135, @@ -1532,7 +1532,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 8, @@ -1562,7 +1562,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -1590,7 +1590,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 22, @@ -1613,7 +1613,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 27, @@ -1636,7 +1636,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 27, diff --git a/tests/testdata/other/output/formats/audit_sarif.json b/tests/testdata/other/output/formats/audit_sarif.json index 37aa8fd4..33b5dca1 100644 --- a/tests/testdata/other/output/formats/audit_sarif.json +++ b/tests/testdata/other/output/formats/audit_sarif.json @@ -82,7 +82,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/dir/ejs-frog-demo" + "uri": "ejs-frog-demo" } } ], @@ -96,7 +96,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/fake-creds.txt" + "uri": "file://ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 1, @@ -120,7 +120,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/fake-creds.txt" + "uri": "file://ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 2, @@ -144,7 +144,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/fake-creds.txt" + "uri": "file://ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 3, @@ -168,7 +168,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 10, @@ -192,7 +192,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 11, @@ -227,7 +227,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/dir/ejs-frog-demo" + "uri": "ejs-frog-demo" } } ], @@ -306,7 +306,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "/dir/ejs-frog-demo" + "uri": "ejs-frog-demo" } } ], @@ -321,7 +321,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/public/js/bootstrap.js" + "uri": "file://ejs-frog-demo/public/js/bootstrap.js" }, "region": { "startLine": 136, @@ -351,7 +351,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/public/js/bootstrap.bundle.js" + "uri": "file://ejs-frog-demo/public/js/bootstrap.bundle.js" }, "region": { "startLine": 135, @@ -381,7 +381,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 8, @@ -411,7 +411,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -439,7 +439,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 21, @@ -462,7 +462,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -485,7 +485,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/server.js" + "uri": "file://ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -682,7 +682,7 @@ { "executionSuccessful": true, "workingDirectory": { - "uri": "/dir/ejs-frog-demo" + "uri": "ejs-frog-demo" } } ], @@ -702,7 +702,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/package.json" + "uri": "file://ejs-frog-demo/package.json" } } } @@ -723,7 +723,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/package.json" + "uri": "file://ejs-frog-demo/package.json" } } } @@ -744,7 +744,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/package.json" + "uri": "file://ejs-frog-demo/package.json" } } } @@ -765,7 +765,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/package.json" + "uri": "file://ejs-frog-demo/package.json" } } } @@ -786,7 +786,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/package.json" + "uri": "file://ejs-frog-demo/package.json" } } } @@ -807,7 +807,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/package.json" + "uri": "file://ejs-frog-demo/package.json" } } } @@ -828,7 +828,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/package.json" + "uri": "file://ejs-frog-demo/package.json" } } } @@ -849,7 +849,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/package.json" + "uri": "file://ejs-frog-demo/package.json" } } } @@ -870,7 +870,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/package.json" + "uri": "file://ejs-frog-demo/package.json" } } } @@ -891,7 +891,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/package.json" + "uri": "file://ejs-frog-demo/package.json" } } } @@ -912,7 +912,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/package.json" + "uri": "file://ejs-frog-demo/package.json" } } } @@ -933,7 +933,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///dir/ejs-frog-demo/package.json" + "uri": "file://ejs-frog-demo/package.json" } } } diff --git a/tests/testdata/other/output/formats/audit_simple_json.json b/tests/testdata/other/output/formats/audit_simple_json.json index 60d846ff..d7f0f13c 100644 --- a/tests/testdata/other/output/formats/audit_simple_json.json +++ b/tests/testdata/other/output/formats/audit_simple_json.json @@ -10,7 +10,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/dir/ejs-frog-demo/package.json" + "file": "ejs-frog-demo/package.json" } } ], @@ -88,7 +88,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/dir/ejs-frog-demo/package.json" + "file": "ejs-frog-demo/package.json" } } ], @@ -133,7 +133,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/dir/ejs-frog-demo/package.json" + "file": "ejs-frog-demo/package.json" } } ], @@ -178,7 +178,7 @@ "name": "express", "version": "4.18.2", "location": { - "file": "/dir/ejs-frog-demo/package.json" + "file": "ejs-frog-demo/package.json" } } ], @@ -224,7 +224,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/dir/ejs-frog-demo/package.json" + "file": "ejs-frog-demo/package.json" } } ], @@ -300,7 +300,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/dir/ejs-frog-demo/package.json" + "file": "ejs-frog-demo/package.json" } } ], @@ -377,7 +377,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/dir/ejs-frog-demo/package.json" + "file": "ejs-frog-demo/package.json" } } ], @@ -453,7 +453,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/dir/ejs-frog-demo/package.json" + "file": "ejs-frog-demo/package.json" } } ], @@ -523,7 +523,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/dir/ejs-frog-demo/package.json" + "file": "ejs-frog-demo/package.json" } } ], @@ -586,7 +586,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/dir/ejs-frog-demo/package.json" + "file": "ejs-frog-demo/package.json" } } ], @@ -663,7 +663,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "/dir/ejs-frog-demo/package.json" + "file": "ejs-frog-demo/package.json" } } ], @@ -729,7 +729,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "/dir/ejs-frog-demo/package.json" + "file": "ejs-frog-demo/package.json" } } ], diff --git a/tests/testdata/other/output/formats/audit_summary.json b/tests/testdata/other/output/formats/audit_summary.json index 48904443..aa2a6458 100644 --- a/tests/testdata/other/output/formats/audit_summary.json +++ b/tests/testdata/other/output/formats/audit_summary.json @@ -1,7 +1,7 @@ { "scans": [ { - "target": "/dir/ejs-frog-demo", + "target": "ejs-frog-demo", "vulnerabilities": { "sca": { "sca": { diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index 4cab9118..02624d14 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -136,7 +136,6 @@ func ChangeWD(t *testing.T, newPath string) string { func ReadOutputFromFile(t *testing.T, path string) string { content, err := os.ReadFile(path) - assert.NoError(t, err) return strings.ReplaceAll(filepath.FromSlash(strings.ReplaceAll(string(content), "\r\n", "\n")), "<"+string(filepath.Separator), " Date: Tue, 23 Jul 2024 19:18:20 +0300 Subject: [PATCH 41/82] try fix win tests --- tests/utils/test_utils.go | 2 +- utils/results/output/securityJobSummary_test.go | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index 02624d14..ac017975 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -137,7 +137,7 @@ func ChangeWD(t *testing.T, newPath string) string { func ReadOutputFromFile(t *testing.T, path string) string { content, err := os.ReadFile(path) assert.NoError(t, err) - return strings.ReplaceAll(filepath.FromSlash(strings.ReplaceAll(string(content), "\r\n", "\n")), "<"+string(filepath.Separator), " Date: Tue, 23 Jul 2024 20:47:57 +0300 Subject: [PATCH 42/82] fix win tests --- tests/utils/test_utils.go | 146 +++++++++++++++++- utils/results/conversion/convertor_test.go | 34 ++-- .../results/output/securityJobSummary_test.go | 10 +- 3 files changed, 157 insertions(+), 33 deletions(-) diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index ac017975..4ccf0620 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -5,14 +5,17 @@ import ( "encoding/xml" "errors" "fmt" - "github.com/jfrog/jfrog-cli-security/utils/formats" "os" "path/filepath" "strconv" - "strings" "testing" "time" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" + "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/owenrumney/go-sarif/v2/sarif" + clientUtils "github.com/jfrog/jfrog-client-go/utils" xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" "github.com/stretchr/testify/require" @@ -134,10 +137,145 @@ func ChangeWD(t *testing.T, newPath string) string { return prevDir } -func ReadOutputFromFile(t *testing.T, path string) string { +func ReadCmdScanResults(t *testing.T, path string) *results.SecurityCommandResults { + content, err := os.ReadFile(path) + assert.NoError(t, err) + var cmdResults *results.SecurityCommandResults + if !assert.NoError(t, json.Unmarshal(content, &cmdResults)) { + return &results.SecurityCommandResults{} + } + // replace paths separators + for _, targetResults := range cmdResults.Targets { + targetResults.Target = filepath.FromSlash(targetResults.Target) + if targetResults.ScaResults != nil { + for i, descriptor := range targetResults.ScaResults.Descriptors { + targetResults.ScaResults.Descriptors[i] = filepath.FromSlash(descriptor) + } + } + if targetResults.JasResults != nil { + convertSarifRunPathsForOS(targetResults.JasResults.ApplicabilityScanResults...) + convertSarifRunPathsForOS(targetResults.JasResults.SecretsScanResults...) + convertSarifRunPathsForOS(targetResults.JasResults.IacScanResults...) + convertSarifRunPathsForOS(targetResults.JasResults.SastScanResults...) + } + } + return cmdResults +} + +func convertSarifRunPathsForOS(runs ...*sarif.Run) { + for _, run := range runs { + for _, invocation := range run.Invocations { + if invocation.WorkingDirectory != nil && invocation.WorkingDirectory.URI != nil { + *invocation.WorkingDirectory.URI = filepath.FromSlash(sarifutils.GetInvocationWorkingDirectory(invocation)) + } + } + for _, result := range run.Results { + for _, location := range result.Locations { + if location != nil && location.PhysicalLocation != nil && location.PhysicalLocation.ArtifactLocation != nil && location.PhysicalLocation.ArtifactLocation.URI != nil { + *location.PhysicalLocation.ArtifactLocation.URI = filepath.FromSlash(sarifutils.GetLocationFileName(location)) + } + } + } + } +} + +func ReadSimpleJsonResults(t *testing.T, path string) formats.SimpleJsonResults { content, err := os.ReadFile(path) assert.NoError(t, err) - return filepath.FromSlash(strings.ReplaceAll(string(content), "\r\n", "\n")) + var results formats.SimpleJsonResults + if !assert.NoError(t, json.Unmarshal(content, &results)) { + return formats.SimpleJsonResults{} + } + // replace paths separators + for _, vulnerability := range results.Vulnerabilities { + convertScaSimpleJsonPathsForOS(&vulnerability.Components, &vulnerability.ImpactPaths, &vulnerability.ImpactedDependencyDetails) + } + for _, violation := range results.SecurityViolations { + convertScaSimpleJsonPathsForOS(&violation.Components, &violation.ImpactPaths, &violation.ImpactedDependencyDetails) + } + for _, licenseViolation := range results.LicensesViolations { + convertScaSimpleJsonPathsForOS(&licenseViolation.Components, &licenseViolation.ImpactPaths, &licenseViolation.ImpactedDependencyDetails) + } + for _, orViolation := range results.OperationalRiskViolations { + convertScaSimpleJsonPathsForOS(&orViolation.Components, nil, &orViolation.ImpactedDependencyDetails) + } + for _, secret := range results.Secrets { + convertJasSimpleJsonPathsForOS(&secret) + } + for _, sast := range results.Sast { + convertJasSimpleJsonPathsForOS(&sast) + } + for _, iac := range results.Iacs { + convertJasSimpleJsonPathsForOS(&iac) + } + return results +} + +func convertJasSimpleJsonPathsForOS(jas *formats.SourceCodeRow) { + if jas == nil { + return + } + jas.Location.File = filepath.FromSlash(jas.Location.File) + for _, codeFlow := range jas.CodeFlow { + for _, location := range codeFlow { + location.File = filepath.FromSlash(location.File) + } + } +} + +func convertScaSimpleJsonPathsForOS(potentialComponents *[]formats.ComponentRow, potentialImpactPaths *[][]formats.ComponentRow, potentialImpactedDependencyDetails *formats.ImpactedDependencyDetails) { + if potentialComponents != nil { + components := *potentialComponents + for _, component := range components { + if component.Location != nil { + component.Location.File = filepath.FromSlash(component.Location.File) + } + } + } + if potentialImpactPaths != nil { + impactPaths := *potentialImpactPaths + for _, impactPath := range impactPaths { + for _, pathComponent := range impactPath { + if pathComponent.Location != nil { + pathComponent.Location.File = filepath.FromSlash(pathComponent.Location.File) + } + } + } + } + if potentialImpactedDependencyDetails != nil { + impactedDependencyDetails := *potentialImpactedDependencyDetails + for _, component := range impactedDependencyDetails.Components { + if component.Location != nil { + component.Location.File = filepath.FromSlash(component.Location.File) + } + } + } +} + +func ReadSarifResults(t *testing.T, path string) *sarif.Report { + content, err := os.ReadFile(path) + assert.NoError(t, err) + var results *sarif.Report + if !assert.NoError(t, json.Unmarshal(content, results)) { + return &sarif.Report{} + } + // replace paths separators + convertSarifRunPathsForOS(results.Runs...) + return results +} + +func ReadSummaryResults(t *testing.T, path string) formats.SummaryResults { + content, err := os.ReadFile(path) + assert.NoError(t, err) + var results formats.SummaryResults + if !assert.NoError(t, json.Unmarshal(content, &results)) { + return formats.SummaryResults{} + } + // replace paths separators + for _, targetResults := range results.Scans { + targetResults.Target = filepath.FromSlash(targetResults.Target) + } + return results } func CreateTestWatch(t *testing.T, policyName string, watchName, severity xrayUtils.Severity) (string, func()) { diff --git a/utils/results/conversion/convertor_test.go b/utils/results/conversion/convertor_test.go index 37c3e789..e91a1879 100644 --- a/utils/results/conversion/convertor_test.go +++ b/utils/results/conversion/convertor_test.go @@ -1,15 +1,16 @@ package conversion import ( - "encoding/json" "fmt" "path/filepath" "testing" - "github.com/jfrog/jfrog-cli-security/tests/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" + + testUtils "github.com/jfrog/jfrog-cli-security/tests/utils" "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/validations" + "github.com/owenrumney/go-sarif/v2/sarif" "github.com/stretchr/testify/assert" ) @@ -41,10 +42,7 @@ func getValidationParams() validations.ValidationParams { } func TestConvertResults(t *testing.T) { - var inputResults *results.SecurityCommandResults - if !assert.NoError(t, json.Unmarshal([]byte(utils.ReadOutputFromFile(t, filepath.Join(testDataDir, "audit_results.json"))), &inputResults)) { - return - } + inputResults := testUtils.ReadCmdScanResults(t, filepath.Join(testDataDir, "audit_results.json")) testCases := []struct { contentFormat conversionFormat @@ -71,21 +69,17 @@ func TestConvertResults(t *testing.T) { switch testCase.contentFormat { case SimpleJson: - validateSimpleJsonConversion(t, []byte(utils.ReadOutputFromFile(t, testCase.expectedContentPath)), inputResults, convertor, validationParams) + validateSimpleJsonConversion(t, testUtils.ReadSimpleJsonResults(t, testCase.expectedContentPath), inputResults, convertor, validationParams) case Sarif: - validateSarifConversion(t, []byte(utils.ReadOutputFromFile(t, testCase.expectedContentPath)), inputResults, convertor, validationParams) + validateSarifConversion(t, testUtils.ReadSarifResults(t, testCase.expectedContentPath), inputResults, convertor, validationParams) case Summary: - validateSummaryConversion(t, []byte(utils.ReadOutputFromFile(t, testCase.expectedContentPath)), inputResults, convertor, validationParams) + validateSummaryConversion(t, testUtils.ReadSummaryResults(t, testCase.expectedContentPath), inputResults, convertor, validationParams) } }) } } -func validateSimpleJsonConversion(t *testing.T, expectedContent []byte, inputResults *results.SecurityCommandResults, convertor *CommandResultsConvertor, validationParams validations.ValidationParams) { - var expectedResults formats.SimpleJsonResults - if !assert.NoError(t, json.Unmarshal(expectedContent, &expectedResults)) { - return - } +func validateSimpleJsonConversion(t *testing.T, expectedResults formats.SimpleJsonResults, inputResults *results.SecurityCommandResults, convertor *CommandResultsConvertor, validationParams validations.ValidationParams) { validationParams.Expected = expectedResults actualResults, err := convertor.ConvertToSimpleJson(inputResults) @@ -97,11 +91,7 @@ func validateSimpleJsonConversion(t *testing.T, expectedContent []byte, inputRes validations.ValidateCommandSimpleJsonOutput(t, validationParams) } -func validateSarifConversion(t *testing.T, expectedContent []byte, inputResults *results.SecurityCommandResults, convertor *CommandResultsConvertor, validationParams validations.ValidationParams) { - var expectedResults *sarif.Report - if !assert.NoError(t, json.Unmarshal(expectedContent, &expectedResults)) { - return - } +func validateSarifConversion(t *testing.T, expectedResults *sarif.Report, inputResults *results.SecurityCommandResults, convertor *CommandResultsConvertor, validationParams validations.ValidationParams) { validationParams.Expected = expectedResults actualResults, err := convertor.ConvertToSarif(inputResults) @@ -113,11 +103,7 @@ func validateSarifConversion(t *testing.T, expectedContent []byte, inputResults validations.ValidateCommandSarifOutput(t, validationParams) } -func validateSummaryConversion(t *testing.T, expectedContent []byte, inputResults *results.SecurityCommandResults, convertor *CommandResultsConvertor, validationParams validations.ValidationParams) { - var expectedResults formats.SummaryResults - if !assert.NoError(t, json.Unmarshal(expectedContent, &expectedResults)) { - return - } +func validateSummaryConversion(t *testing.T, expectedResults formats.SummaryResults, inputResults *results.SecurityCommandResults, convertor *CommandResultsConvertor, validationParams validations.ValidationParams) { validationParams.Expected = expectedResults actualResults, err := convertor.ConvertToSummary(inputResults) diff --git a/utils/results/output/securityJobSummary_test.go b/utils/results/output/securityJobSummary_test.go index 40a3d74b..86ce1653 100644 --- a/utils/results/output/securityJobSummary_test.go +++ b/utils/results/output/securityJobSummary_test.go @@ -6,7 +6,6 @@ import ( "strings" "testing" - "github.com/jfrog/jfrog-cli-security/tests/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/stretchr/testify/assert" ) @@ -124,7 +123,7 @@ func TestConvertSummaryToString(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { // Read expected content from file - expectedContent := readOutputFile(t, testCase.expectedContentPath) + expectedContent := readOutputFromFile(t, testCase.expectedContentPath) summary, err := ConvertSummaryToString(testCase.summary) assert.NoError(t, err) assert.Equal(t, expectedContent, summary) @@ -132,9 +131,10 @@ func TestConvertSummaryToString(t *testing.T) { } } -func readOutputFile(t *testing.T, path string) string { - expectedContent := utils.ReadOutputFromFile(t, path) - return strings.ReplaceAll(expectedContent, "<"+string(filepath.Separator), " Date: Tue, 23 Jul 2024 21:28:38 +0300 Subject: [PATCH 43/82] try fix tests --- .../other/output/formats/audit_results.json | 46 +++++++-------- .../other/output/formats/audit_sarif.json | 56 +++++++++---------- .../output/formats/audit_simple_json.json | 24 ++++---- .../other/output/formats/audit_summary.json | 2 +- tests/utils/test_utils.go | 2 +- 5 files changed, 65 insertions(+), 65 deletions(-) diff --git a/tests/testdata/other/output/formats/audit_results.json b/tests/testdata/other/output/formats/audit_results.json index deb8540a..1f15f8c8 100644 --- a/tests/testdata/other/output/formats/audit_results.json +++ b/tests/testdata/other/output/formats/audit_results.json @@ -4,12 +4,12 @@ "multi_scan_id": "7d5e4733-3f93-11ef-8147-e610d09d7daa", "targets": [ { - "target": "ejs-frog-demo", + "target": "/Users/user/ejs-frog-demo", "technology": "npm", "sca_scans": { "is_multiple_root_project": false, "descriptors": [ - "ejs-frog-demo/package.json" + "/Users/user/ejs-frog-demo/package.json" ], "xray_scan": [ { @@ -964,7 +964,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "ejs-frog-demo" + "uri": "/Users/user/ejs-frog-demo" } } ], @@ -978,7 +978,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1009,7 +1009,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1061,7 +1061,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 1, @@ -1099,7 +1099,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 15, @@ -1123,7 +1123,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 27, @@ -1229,7 +1229,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "ejs-frog-demo" + "uri": "/Users/user/ejs-frog-demo" } } ], @@ -1243,7 +1243,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/fake-creds.txt" + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 1, @@ -1267,7 +1267,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/fake-creds.txt" + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 2, @@ -1291,7 +1291,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/fake-creds.txt" + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 3, @@ -1315,7 +1315,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 10, @@ -1339,7 +1339,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 11, @@ -1376,7 +1376,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "ejs-frog-demo" + "uri": "/Users/user/ejs-frog-demo" } } ], @@ -1457,7 +1457,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "ejs-frog-demo" + "uri": "/Users/user/ejs-frog-demo" } } ], @@ -1472,7 +1472,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/public/js/bootstrap.js" + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" }, "region": { "startLine": 136, @@ -1502,7 +1502,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/public/js/bootstrap.bundle.js" + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" }, "region": { "startLine": 135, @@ -1532,7 +1532,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 8, @@ -1562,7 +1562,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -1590,7 +1590,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 22, @@ -1613,7 +1613,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 27, @@ -1636,7 +1636,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 27, diff --git a/tests/testdata/other/output/formats/audit_sarif.json b/tests/testdata/other/output/formats/audit_sarif.json index 33b5dca1..d37a0f55 100644 --- a/tests/testdata/other/output/formats/audit_sarif.json +++ b/tests/testdata/other/output/formats/audit_sarif.json @@ -82,7 +82,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "ejs-frog-demo" + "uri": "/Users/user/ejs-frog-demo" } } ], @@ -96,7 +96,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/fake-creds.txt" + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 1, @@ -120,7 +120,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/fake-creds.txt" + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 2, @@ -144,7 +144,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/fake-creds.txt" + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" }, "region": { "startLine": 3, @@ -168,7 +168,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 10, @@ -192,7 +192,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 11, @@ -227,7 +227,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "ejs-frog-demo" + "uri": "/Users/user/ejs-frog-demo" } } ], @@ -306,7 +306,7 @@ ], "executionSuccessful": true, "workingDirectory": { - "uri": "ejs-frog-demo" + "uri": "/Users/user/ejs-frog-demo" } } ], @@ -321,7 +321,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/public/js/bootstrap.js" + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" }, "region": { "startLine": 136, @@ -351,7 +351,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/public/js/bootstrap.bundle.js" + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" }, "region": { "startLine": 135, @@ -381,7 +381,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 8, @@ -411,7 +411,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -439,7 +439,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 21, @@ -462,7 +462,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -485,7 +485,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/server.js" + "uri": "file:///Users/user/ejs-frog-demo/server.js" }, "region": { "startLine": 26, @@ -682,7 +682,7 @@ { "executionSuccessful": true, "workingDirectory": { - "uri": "ejs-frog-demo" + "uri": "/Users/user/ejs-frog-demo" } } ], @@ -702,7 +702,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/package.json" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -723,7 +723,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/package.json" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -744,7 +744,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/package.json" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -765,7 +765,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/package.json" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -786,7 +786,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/package.json" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -807,7 +807,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/package.json" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -828,7 +828,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/package.json" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -849,7 +849,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/package.json" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -870,7 +870,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/package.json" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -891,7 +891,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/package.json" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -912,7 +912,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/package.json" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } @@ -933,7 +933,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file://ejs-frog-demo/package.json" + "uri": "file:///Users/user/ejs-frog-demo/package.json" } } } diff --git a/tests/testdata/other/output/formats/audit_simple_json.json b/tests/testdata/other/output/formats/audit_simple_json.json index d7f0f13c..44a43ac1 100644 --- a/tests/testdata/other/output/formats/audit_simple_json.json +++ b/tests/testdata/other/output/formats/audit_simple_json.json @@ -10,7 +10,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "ejs-frog-demo/package.json" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -88,7 +88,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "ejs-frog-demo/package.json" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -133,7 +133,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "ejs-frog-demo/package.json" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -178,7 +178,7 @@ "name": "express", "version": "4.18.2", "location": { - "file": "ejs-frog-demo/package.json" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -224,7 +224,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "ejs-frog-demo/package.json" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -300,7 +300,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "ejs-frog-demo/package.json" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -377,7 +377,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "ejs-frog-demo/package.json" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -453,7 +453,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "ejs-frog-demo/package.json" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -523,7 +523,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "ejs-frog-demo/package.json" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -586,7 +586,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "ejs-frog-demo/package.json" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -663,7 +663,7 @@ "name": "ejs", "version": "3.1.6", "location": { - "file": "ejs-frog-demo/package.json" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], @@ -729,7 +729,7 @@ "name": "lodash", "version": "4.17.0", "location": { - "file": "ejs-frog-demo/package.json" + "file": "/Users/user/ejs-frog-demo/package.json" } } ], diff --git a/tests/testdata/other/output/formats/audit_summary.json b/tests/testdata/other/output/formats/audit_summary.json index aa2a6458..d0da55a1 100644 --- a/tests/testdata/other/output/formats/audit_summary.json +++ b/tests/testdata/other/output/formats/audit_summary.json @@ -1,7 +1,7 @@ { "scans": [ { - "target": "ejs-frog-demo", + "target": "/Users/user/ejs-frog-demo", "vulnerabilities": { "sca": { "sca": { diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index 4ccf0620..fe3026e8 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -256,7 +256,7 @@ func ReadSarifResults(t *testing.T, path string) *sarif.Report { content, err := os.ReadFile(path) assert.NoError(t, err) var results *sarif.Report - if !assert.NoError(t, json.Unmarshal(content, results)) { + if !assert.NoError(t, json.Unmarshal(content, &results)) { return &sarif.Report{} } // replace paths separators From 70b74c45ffbe2a62468b9fdb46a1e75911413513 Mon Sep 17 00:00:00 2001 From: attiasas Date: Wed, 24 Jul 2024 12:20:02 +0300 Subject: [PATCH 44/82] try fix tests --- tests/utils/test_utils.go | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index fe3026e8..f440e127 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "strconv" + "strings" "testing" "time" @@ -172,7 +173,7 @@ func convertSarifRunPathsForOS(runs ...*sarif.Run) { for _, result := range run.Results { for _, location := range result.Locations { if location != nil && location.PhysicalLocation != nil && location.PhysicalLocation.ArtifactLocation != nil && location.PhysicalLocation.ArtifactLocation.URI != nil { - *location.PhysicalLocation.ArtifactLocation.URI = filepath.FromSlash(sarifutils.GetLocationFileName(location)) + *location.PhysicalLocation.ArtifactLocation.URI = getJasConvertedPath(sarifutils.GetLocationFileName(location)) } } } @@ -188,16 +189,16 @@ func ReadSimpleJsonResults(t *testing.T, path string) formats.SimpleJsonResults } // replace paths separators for _, vulnerability := range results.Vulnerabilities { - convertScaSimpleJsonPathsForOS(&vulnerability.Components, &vulnerability.ImpactPaths, &vulnerability.ImpactedDependencyDetails) + convertScaSimpleJsonPathsForOS(&vulnerability.Components, &vulnerability.ImpactPaths, &vulnerability.ImpactedDependencyDetails, &vulnerability.Cves) } for _, violation := range results.SecurityViolations { - convertScaSimpleJsonPathsForOS(&violation.Components, &violation.ImpactPaths, &violation.ImpactedDependencyDetails) + convertScaSimpleJsonPathsForOS(&violation.Components, &violation.ImpactPaths, &violation.ImpactedDependencyDetails, &violation.Cves) } for _, licenseViolation := range results.LicensesViolations { - convertScaSimpleJsonPathsForOS(&licenseViolation.Components, &licenseViolation.ImpactPaths, &licenseViolation.ImpactedDependencyDetails) + convertScaSimpleJsonPathsForOS(&licenseViolation.Components, &licenseViolation.ImpactPaths, &licenseViolation.ImpactedDependencyDetails, nil) } for _, orViolation := range results.OperationalRiskViolations { - convertScaSimpleJsonPathsForOS(&orViolation.Components, nil, &orViolation.ImpactedDependencyDetails) + convertScaSimpleJsonPathsForOS(&orViolation.Components, nil, &orViolation.ImpactedDependencyDetails, nil) } for _, secret := range results.Secrets { convertJasSimpleJsonPathsForOS(&secret) @@ -215,15 +216,15 @@ func convertJasSimpleJsonPathsForOS(jas *formats.SourceCodeRow) { if jas == nil { return } - jas.Location.File = filepath.FromSlash(jas.Location.File) + jas.Location.File = getJasConvertedPath(jas.Location.File) for _, codeFlow := range jas.CodeFlow { for _, location := range codeFlow { - location.File = filepath.FromSlash(location.File) + location.File = getJasConvertedPath(location.File) } } } -func convertScaSimpleJsonPathsForOS(potentialComponents *[]formats.ComponentRow, potentialImpactPaths *[][]formats.ComponentRow, potentialImpactedDependencyDetails *formats.ImpactedDependencyDetails) { +func convertScaSimpleJsonPathsForOS(potentialComponents *[]formats.ComponentRow, potentialImpactPaths *[][]formats.ComponentRow, potentialImpactedDependencyDetails *formats.ImpactedDependencyDetails, potentialCves *[]formats.CveRow) { if potentialComponents != nil { components := *potentialComponents for _, component := range components { @@ -250,6 +251,16 @@ func convertScaSimpleJsonPathsForOS(potentialComponents *[]formats.ComponentRow, } } } + if potentialCves != nil { + cves := *potentialCves + for _, cve := range cves { + if cve.Applicability != nil { + for _, evidence := range cve.Applicability.Evidence { + evidence.Location.File = filepath.FromSlash(evidence.Location.File) + } + } + } + } } func ReadSarifResults(t *testing.T, path string) *sarif.Report { @@ -278,6 +289,10 @@ func ReadSummaryResults(t *testing.T, path string) formats.SummaryResults { return results } +func getJasConvertedPath(pathToConvert string) string { + return fmt.Sprintf("file://%s", filepath.FromSlash(strings.TrimPrefix(pathToConvert, "file://"))) +} + func CreateTestWatch(t *testing.T, policyName string, watchName, severity xrayUtils.Severity) (string, func()) { xrayManager, err := xray.CreateXrayServiceManager(configTests.XrDetails) require.NoError(t, err) From 7a810c171d97a6871257938127fc29175f7a03b2 Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 28 Jul 2024 12:07:20 +0300 Subject: [PATCH 45/82] fix merge and a tech bug --- commands/curation/curationaudit.go | 4 ++-- commands/curation/curationaudit_test.go | 2 +- commands/scan/buildscan.go | 2 +- commands/scan/dockerscan.go | 2 +- commands/scan/scan.go | 2 +- utils/results/output/securityJobSummary.go | 14 +++++++++----- utils/results/results.go | 12 ++++++++++-- 7 files changed, 25 insertions(+), 13 deletions(-) diff --git a/commands/curation/curationaudit.go b/commands/curation/curationaudit.go index 5ddc6a59..23a651b2 100644 --- a/commands/curation/curationaudit.go +++ b/commands/curation/curationaudit.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - "github.com/jfrog/jfrog-cli-security/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats" "net/http" "os" "path/filepath" @@ -243,7 +243,7 @@ func (ca *CurationAuditCommand) Run() (err error) { err = errors.Join(err, printResult(ca.OutputFormat(), projectPath, packagesStatus.packagesStatus)) } - err = errors.Join(err, utils.RecordSecurityCommandOutput(utils.ScanCommandSummaryResult{Results: convertResultsToSummary(results), Section: utils.Curation})) + err = errors.Join(err, output.RecordSecurityCommandOutput(output.ScanCommandSummaryResult{Results: convertResultsToSummary(results), Section: output.Curation})) return } diff --git a/commands/curation/curationaudit_test.go b/commands/curation/curationaudit_test.go index 3beb3e91..21aae4fe 100644 --- a/commands/curation/curationaudit_test.go +++ b/commands/curation/curationaudit_test.go @@ -3,7 +3,7 @@ package curation import ( "encoding/json" "fmt" - "github.com/jfrog/jfrog-cli-security/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats" "net/http" "net/http/httptest" "os" diff --git a/commands/scan/buildscan.go b/commands/scan/buildscan.go index 93e0deab..c37b9f3c 100644 --- a/commands/scan/buildscan.go +++ b/commands/scan/buildscan.go @@ -177,7 +177,7 @@ func (bsc *BuildScanCommand) runBuildScanAndPrintResults(xrayManager *xray.XrayS } } } - err = output.RecordSecurityCommandOutput(output.Build, cmdResults) + err = output.RecordSecurityCommandResultOutput(output.Build, cmdResults) return } diff --git a/commands/scan/dockerscan.go b/commands/scan/dockerscan.go index ad0930b5..e6f6ef50 100644 --- a/commands/scan/dockerscan.go +++ b/commands/scan/dockerscan.go @@ -104,7 +104,7 @@ func (dsc *DockerScanCommand) Run() (err error) { cmdResults.Targets[i].Name = dsc.imageTag // scanResults.Scans[i].Target = dsc.imageTag } - return output.RecordSecurityCommandOutput(output.Binary, cmdResults) + return output.RecordSecurityCommandResultOutput(output.Binary, cmdResults) }) } diff --git a/commands/scan/scan.go b/commands/scan/scan.go index cbbff1a0..8eaac23e 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -180,7 +180,7 @@ func (scanCmd *ScanCommand) indexFile(filePath string) (*xrayUtils.BinaryGraphNo func (scanCmd *ScanCommand) Run() (err error) { return scanCmd.RunAndRecordResults(func(cmdResults *results.SecurityCommandResults) error { - return output.RecordSecurityCommandOutput(output.Binary, cmdResults) + return output.RecordSecurityCommandResultOutput(output.Binary, cmdResults) }) } diff --git a/utils/results/output/securityJobSummary.go b/utils/results/output/securityJobSummary.go index 38ce3e6c..e4b00039 100644 --- a/utils/results/output/securityJobSummary.go +++ b/utils/results/output/securityJobSummary.go @@ -79,7 +79,15 @@ func CreateCommandSummaryResult(section SecuritySummarySection, cmdResults *resu } // Record the security command output -func RecordSecurityCommandOutput(section SecuritySummarySection, cmdResults *results.SecurityCommandResults) (err error) { +func RecordSecurityCommandResultOutput(section SecuritySummarySection, cmdResults *results.SecurityCommandResults) (err error) { + summary, err := CreateCommandSummaryResult(section, cmdResults) + if err != nil { + return + } + return RecordSecurityCommandOutput(summary) +} + +func RecordSecurityCommandOutput(summary ScanCommandSummaryResult) (err error) { if !commandsummary.ShouldRecordSummary() { return } @@ -91,10 +99,6 @@ func RecordSecurityCommandOutput(section SecuritySummarySection, cmdResults *res if err != nil { return } - summary, err := CreateCommandSummaryResult(section, cmdResults) - if err != nil { - return - } summary.WorkingDirectory = wd return manager.Record(summary) } diff --git a/utils/results/results.go b/utils/results/results.go index 6ca4e6f4..12380943 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -177,8 +177,16 @@ func (sr *TargetResults) GetTechnologies() []techutils.Technology { return technologiesSet.ToSlice() } for _, scaResult := range sr.ScaResults.XrayResults { - if scaResult.ScannedPackageType != "" { - technologiesSet.Add(techutils.Technology(strings.ToLower(scaResult.ScannedPackageType))) + for _, vulnerability := range scaResult.Vulnerabilities { + // if tech, ok := techutils.Technology(vulnerability.Technology); ok { + if tech := techutils.Technology(strings.ToLower(vulnerability.Technology)); tech != "" { + technologiesSet.Add(tech) + } + } + for _, violation := range scaResult.Violations { + if tech := techutils.Technology(strings.ToLower(violation.Technology)); tech != "" { + technologiesSet.Add(tech) + } } } return technologiesSet.ToSlice() From 8844dd6a4d7bcc2ce1f3e1c2dc9255acaaf6655d Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 29 Jul 2024 12:25:20 +0300 Subject: [PATCH 46/82] try fix tests --- utils/results/common.go | 29 +- utils/results/conversion/convertor.go | 110 +------ .../conversion/sarifparser/sarifparser.go | 6 +- .../simplejsonparser/simplejsonparser.go | 270 +++++++++++++----- .../conversion/summaryparser/summaryparser.go | 6 +- .../conversion/tableparser/tableparser.go | 10 +- 6 files changed, 242 insertions(+), 189 deletions(-) diff --git a/utils/results/common.go b/utils/results/common.go index c53f4192..f8109c0f 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -21,9 +21,9 @@ import ( const ( customLicenseViolationId = "custom_license_violation" - rootIndex = 0 - directDependencyIndex = 1 - directDependencyPathLength = 2 + RootIndex = 0 + DirectDependencyIndex = 1 + DirectDependencyPathLength = 2 nodeModules = "node_modules" ) @@ -262,10 +262,6 @@ func GetIssueIdentifier(cvesRow []formats.CveRow, issueId string, delimiter stri return identifier } -func GetScaIssueId(depName, version, issueId string) string { - return fmt.Sprintf("%s_%s_%s", issueId, depName, version) -} - func ConvertCvesWithApplicability(cves []services.Cve, entitledForJas bool, applicabilityRuns []*sarif.Run, components map[string]services.Component) (convertedCves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus) { convertedCves = convertCves(cves) for i := range convertedCves { @@ -403,9 +399,9 @@ func AppendUniqueImpactPaths(target [][]services.ImpactPathNode, source [][]serv // getImpactPathKey return a key that is used as a key to identify and deduplicate impact paths. // If an impact path length is equal to directDependencyPathLength, then the direct dependency is the key, and it's in the directDependencyIndex place. func getImpactPathKey(path []services.ImpactPathNode) string { - key := path[rootIndex].ComponentId - if len(path) == directDependencyPathLength { - key = path[directDependencyIndex].ComponentId + key := path[RootIndex].ComponentId + if len(path) == DirectDependencyPathLength { + key = path[DirectDependencyIndex].ComponentId } return key } @@ -535,6 +531,19 @@ func getApplicabilityStatusFromRule(rule *sarif.ReportingDescriptor) jasutils.Ap return "" } +func GetDependencyId(depName, version string) string { + return fmt.Sprintf("%s:%s", depName, version) +} + +func GetScaIssueId(depName, version, issueId string) string { + return fmt.Sprintf("%s_%s_%s", issueId, depName, version) +} + +// GetUniqueKey returns a unique string key of format "vulnerableDependency:vulnerableVersion:xrayID:fixVersionExist" +func GetUniqueKey(vulnerableDependency, vulnerableVersion, xrayID string, fixVersionExist bool) string { + return strings.Join([]string{vulnerableDependency, vulnerableVersion, xrayID, strconv.FormatBool(fixVersionExist)}, ":") +} + // Relevant only when "third-party-contextual-analysis" flag is on, // which mean we scan the environment folders as well (node_modules for example...) // When a certain package is reported applicable, and the evidence found diff --git a/utils/results/conversion/convertor.go b/utils/results/conversion/convertor.go index 64941699..d743cd85 100644 --- a/utils/results/conversion/convertor.go +++ b/utils/results/conversion/convertor.go @@ -1,10 +1,8 @@ package conversion import ( - "strconv" "strings" - "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/results/conversion/sarifparser" @@ -44,9 +42,9 @@ func NewCommandResultsConvertor(params ResultConvertParams) *CommandResultsConve // Parse a stream of results and convert to the desired format type ResultsStreamFormatParser interface { // Reset the convertor to start converting a new command results - Reset(multiScanId, xrayVersion string, entitledForJas bool) error + Reset(multiScanId, xrayVersion string, entitledForJas, multipleTargets bool) error // Will be called for each scan target (indicating the current is done parsing and starting to parse a new scan) - ParseNewScanResultsMetadata(target string, errors ...error) error + ParseNewTargetResults(target string, errors ...error) error // Parse SCA content to the current scan target ParseViolations(target string, tech techutils.Technology, violations []services.Violation, applicabilityRuns ...*sarif.Run) error ParseVulnerabilities(target string, tech techutils.Technology, vulnerabilities []services.Vulnerability, applicabilityRuns ...*sarif.Run) error @@ -58,7 +56,7 @@ type ResultsStreamFormatParser interface { } func (c *CommandResultsConvertor) ConvertToSimpleJson(cmdResults *results.SecurityCommandResults) (simpleJsonResults formats.SimpleJsonResults, err error) { - parser := simplejsonparser.NewCmdResultsSimpleJsonConverter(false) + parser := simplejsonparser.NewCmdResultsSimpleJsonConverter(false, c.Params.SimplifiedOutput) err = c.parseCommandResults(parser, cmdResults) if err != nil { return @@ -111,11 +109,11 @@ func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormat if c.Params.IsMultipleRoots != nil { multipleTargets = *c.Params.IsMultipleRoots } - if err = parser.Reset(cmdResults.MultiScanId, cmdResults.XrayVersion, jasEntitled); err != nil { + if err = parser.Reset(cmdResults.MultiScanId, cmdResults.XrayVersion, jasEntitled, multipleTargets); err != nil { return } for _, targetScansResults := range cmdResults.Targets { - if err = parser.ParseNewScanResultsMetadata(targetScansResults.Target, targetScansResults.Errors...); err != nil { + if err = parser.ParseNewTargetResults(targetScansResults.Target, targetScansResults.Errors...); err != nil { return } if targetScansResults.ScaResults != nil { @@ -139,28 +137,20 @@ func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormat return } -func (c *CommandResultsConvertor) parseScaResults(parser ResultsStreamFormatParser, targetScansResults *results.TargetResults, jasEntitled, multipleTargets bool) (err error) { +func (c *CommandResultsConvertor) parseScaResults(parser ResultsStreamFormatParser, targetScansResults *results.TargetResults, jasEntitled bool) (err error) { for _, scaResults := range targetScansResults.ScaResults.XrayResults { actualTarget := getScaScanTarget(targetScansResults.ScaResults, targetScansResults.Target) var applicableRuns []*sarif.Run if jasEntitled && targetScansResults.JasResults != nil { applicableRuns = targetScansResults.JasResults.ApplicabilityScanResults } - vulnerabilities := scaResults.Vulnerabilities - if c.Params.SimplifiedOutput { - vulnerabilities = simplifyVulnerabilities(vulnerabilities, multipleTargets) - } - if len(vulnerabilities) > 0 { - if err = parser.ParseVulnerabilities(actualTarget, targetScansResults.Technology, vulnerabilities, applicableRuns...); err != nil { + if len(scaResults.Vulnerabilities) > 0 { + if err = parser.ParseVulnerabilities(actualTarget, targetScansResults.Technology, scaResults.Vulnerabilities, applicableRuns...); err != nil { return } } - violations := scaResults.Violations - if c.Params.SimplifiedOutput { - violations = simplifyViolations(violations, multipleTargets) - } - if len(violations) > 0 { - if err = parser.ParseViolations(actualTarget, targetScansResults.Technology, violations, applicableRuns...); err != nil { + if len(scaResults.Violations) > 0 { + if err = parser.ParseViolations(actualTarget, targetScansResults.Technology, scaResults.Violations, applicableRuns...); err != nil { return } } else if len(c.Params.AllowedLicenses) > 0 { @@ -199,83 +189,3 @@ func getScaScanTarget(scaResults *results.ScaScanResults, target string) string } return target } - -// simplifyViolations returns a new slice of services.Violations that contains only the unique violations from the input slice -// The uniqueness of the violations is determined by the GetUniqueKey function -func simplifyViolations(scanViolations []services.Violation, multipleRoots bool) []services.Violation { - var uniqueViolations = make(map[string]*services.Violation) - for _, violation := range scanViolations { - for vulnerableComponentId := range violation.Components { - vulnerableDependency, vulnerableVersion, _ := techutils.SplitComponentId(vulnerableComponentId) - packageKey := GetUniqueKey(vulnerableDependency, vulnerableVersion, violation.IssueId, len(violation.Components[vulnerableComponentId].FixedVersions) > 0) - if uniqueVulnerability, exist := uniqueViolations[packageKey]; exist { - fixedVersions := utils.UniqueUnion(uniqueVulnerability.Components[vulnerableComponentId].FixedVersions, violation.Components[vulnerableComponentId].FixedVersions...) - impactPaths := results.AppendUniqueImpactPaths(uniqueVulnerability.Components[vulnerableComponentId].ImpactPaths, violation.Components[vulnerableComponentId].ImpactPaths, multipleRoots) - uniqueViolations[packageKey].Components[vulnerableComponentId] = services.Component{ - FixedVersions: fixedVersions, - ImpactPaths: impactPaths, - } - continue - } - uniqueViolations[packageKey] = &services.Violation{ - Summary: violation.Summary, - Severity: violation.Severity, - ViolationType: violation.ViolationType, - Components: map[string]services.Component{vulnerableComponentId: violation.Components[vulnerableComponentId]}, - WatchName: violation.WatchName, - IssueId: violation.IssueId, - Cves: violation.Cves, - LicenseKey: violation.LicenseKey, - LicenseName: violation.LicenseName, - Technology: violation.Technology, - } - } - } - // convert map to slice - result := make([]services.Violation, 0, len(uniqueViolations)) - for _, v := range uniqueViolations { - result = append(result, *v) - } - return result -} - -// simplifyVulnerabilities returns a new slice of services.Vulnerability that contains only the unique vulnerabilities from the input slice -// The uniqueness of the vulnerabilities is determined by the GetUniqueKey function -func simplifyVulnerabilities(scanVulnerabilities []services.Vulnerability, multipleRoots bool) []services.Vulnerability { - var uniqueVulnerabilities = make(map[string]*services.Vulnerability) - for _, vulnerability := range scanVulnerabilities { - for vulnerableComponentId := range vulnerability.Components { - vulnerableDependency, vulnerableVersion, _ := techutils.SplitComponentId(vulnerableComponentId) - packageKey := GetUniqueKey(vulnerableDependency, vulnerableVersion, vulnerability.IssueId, len(vulnerability.Components[vulnerableComponentId].FixedVersions) > 0) - if uniqueVulnerability, exist := uniqueVulnerabilities[packageKey]; exist { - fixedVersions := utils.UniqueUnion(uniqueVulnerability.Components[vulnerableComponentId].FixedVersions, vulnerability.Components[vulnerableComponentId].FixedVersions...) - impactPaths := results.AppendUniqueImpactPaths(uniqueVulnerability.Components[vulnerableComponentId].ImpactPaths, vulnerability.Components[vulnerableComponentId].ImpactPaths, multipleRoots) - uniqueVulnerabilities[packageKey].Components[vulnerableComponentId] = services.Component{ - FixedVersions: fixedVersions, - ImpactPaths: impactPaths, - } - continue - } - uniqueVulnerabilities[packageKey] = &services.Vulnerability{ - Cves: vulnerability.Cves, - Severity: vulnerability.Severity, - Components: map[string]services.Component{vulnerableComponentId: vulnerability.Components[vulnerableComponentId]}, - IssueId: vulnerability.IssueId, - Technology: vulnerability.Technology, - ExtendedInformation: vulnerability.ExtendedInformation, - Summary: vulnerability.Summary, - } - } - } - // convert map to slice - result := make([]services.Vulnerability, 0, len(uniqueVulnerabilities)) - for _, v := range uniqueVulnerabilities { - result = append(result, *v) - } - return result -} - -// GetUniqueKey returns a unique string key of format "vulnerableDependency:vulnerableVersion:xrayID:fixVersionExist" -func GetUniqueKey(vulnerableDependency, vulnerableVersion, xrayID string, fixVersionExist bool) string { - return strings.Join([]string{vulnerableDependency, vulnerableVersion, xrayID, strconv.FormatBool(fixVersionExist)}, ":") -} diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index 6ec89fc7..386383e7 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -53,13 +53,13 @@ func (sc *CmdResultsSarifConverter) Get() (*sarif.Report, error) { return sarifutils.NewReport() } // Flush the current run - if err := sc.ParseNewScanResultsMetadata("", nil); err != nil { + if err := sc.ParseNewTargetResults("", nil); err != nil { return sarifutils.NewReport() } return sc.current, nil } -func (sc *CmdResultsSarifConverter) Reset(_, xrayVersion string, entitledForJas bool) (err error) { +func (sc *CmdResultsSarifConverter) Reset(_, xrayVersion string, entitledForJas, _ bool) (err error) { sc.current, err = sarifutils.NewReport() if err != nil { return @@ -72,7 +72,7 @@ func (sc *CmdResultsSarifConverter) Reset(_, xrayVersion string, entitledForJas return } -func (sc *CmdResultsSarifConverter) ParseNewScanResultsMetadata(target string, errors ...error) (err error) { +func (sc *CmdResultsSarifConverter) ParseNewTargetResults(target string, errors ...error) (err error) { if sc.current == nil { return results.ConvertorResetErr } diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go index 118ddfea..69349d7e 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go @@ -4,6 +4,7 @@ import ( "sort" "strconv" + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" @@ -17,31 +18,39 @@ import ( type CmdResultsSimpleJsonConverter struct { // If supported, pretty print the output text pretty bool + // If true, the output will contain only unique issues (ignoring the same issue in different locations) + uniqueScaIssues bool // Current stream parse cache information current *formats.SimpleJsonResults // General information on the current command results entitledForJas bool + multipleRoots bool } -func NewCmdResultsSimpleJsonConverter(pretty bool) *CmdResultsSimpleJsonConverter { - return &CmdResultsSimpleJsonConverter{pretty: pretty} +func NewCmdResultsSimpleJsonConverter(pretty, uniqueScaIssues bool) *CmdResultsSimpleJsonConverter { + return &CmdResultsSimpleJsonConverter{pretty: pretty, uniqueScaIssues: uniqueScaIssues} } func (sjc *CmdResultsSimpleJsonConverter) Get() *formats.SimpleJsonResults { if sjc.current == nil { return nil } + if sjc.uniqueScaIssues { + sjc.current.Vulnerabilities = removeScaDuplications(sjc.current.Vulnerabilities, sjc.multipleRoots) + sjc.current.SecurityViolations = removeScaDuplications(sjc.current.SecurityViolations, sjc.multipleRoots) + } sortResults(sjc.current) return sjc.current } -func (sjc *CmdResultsSimpleJsonConverter) Reset(multiScanId, _ string, entitledForJas bool) (err error) { +func (sjc *CmdResultsSimpleJsonConverter) Reset(multiScanId, _ string, entitledForJas, multipleTargets bool) (err error) { sjc.current = &formats.SimpleJsonResults{MultiScanId: multiScanId} sjc.entitledForJas = entitledForJas + sjc.multipleRoots = multipleTargets return } -func (sjc *CmdResultsSimpleJsonConverter) ParseNewScanResultsMetadata(target string, errors ...error) (err error) { +func (sjc *CmdResultsSimpleJsonConverter) ParseNewTargetResults(target string, errors ...error) (err error) { if sjc.current == nil { return results.ConvertorResetErr } @@ -339,6 +348,195 @@ func codeFlowToLocationFlow(flows []*sarif.CodeFlow, invocations []*sarif.Invoca return } +func convertJfrogResearchInformation(extendedInfo *services.ExtendedInformation) *formats.JfrogResearchInformation { + if extendedInfo == nil { + return nil + } + var severityReasons []formats.JfrogResearchSeverityReason + for _, severityReason := range extendedInfo.JfrogResearchSeverityReasons { + severityReasons = append(severityReasons, formats.JfrogResearchSeverityReason{ + Name: severityReason.Name, + Description: severityReason.Description, + IsPositive: severityReason.IsPositive, + }) + } + return &formats.JfrogResearchInformation{ + Summary: extendedInfo.ShortDescription, + Details: extendedInfo.FullDescription, + SeverityDetails: formats.SeverityDetails{Severity: extendedInfo.JfrogResearchSeverity}, + SeverityReasons: severityReasons, + Remediation: extendedInfo.Remediation, + } +} + +type operationalRiskViolationReadableData struct { + isEol string + cadence string + commits string + committers string + eolMessage string + riskReason string + latestVersion string + newerVersions string +} + +func getOperationalRiskViolationReadableData(violation services.Violation) *operationalRiskViolationReadableData { + isEol, cadence, commits, committers, newerVersions, latestVersion := "N/A", "N/A", "N/A", "N/A", "N/A", "N/A" + if violation.IsEol != nil { + isEol = strconv.FormatBool(*violation.IsEol) + } + if violation.Cadence != nil { + cadence = strconv.FormatFloat(*violation.Cadence, 'f', -1, 64) + } + if violation.Committers != nil { + committers = strconv.FormatInt(int64(*violation.Committers), 10) + } + if violation.Commits != nil { + commits = strconv.FormatInt(*violation.Commits, 10) + } + if violation.NewerVersions != nil { + newerVersions = strconv.FormatInt(int64(*violation.NewerVersions), 10) + } + if violation.LatestVersion != "" { + latestVersion = violation.LatestVersion + } + return &operationalRiskViolationReadableData{ + isEol: isEol, + cadence: cadence, + commits: commits, + committers: committers, + eolMessage: violation.EolMessage, + riskReason: violation.RiskReason, + latestVersion: latestVersion, + newerVersions: newerVersions, + } +} + +// Returns a new slice that contains only the unique issues from the input slice +// The uniqueness of the violations is determined by the GetUniqueKey function +func removeScaDuplications(issues []formats.VulnerabilityOrViolationRow, multipleRoots bool) []formats.VulnerabilityOrViolationRow { + var uniqueIssues = make(map[string]*formats.VulnerabilityOrViolationRow) + for _, issue := range issues { + packageKey := results.GetUniqueKey(issue.ImpactedDependencyDetails.ImpactedDependencyName, issue.ImpactedDependencyDetails.ImpactedDependencyVersion, issue.IssueId, len(issue.FixedVersions) > 0) + if uniqueIssue, exist := uniqueIssues[packageKey]; exist { + // combine attributes from the same issue + uniqueIssue.FixedVersions = utils.UniqueUnion(uniqueIssue.FixedVersions, issue.FixedVersions...) + uniqueIssue.ImpactPaths = AppendImpactPathsIfUnique(uniqueIssue.ImpactPaths, issue.ImpactPaths, multipleRoots) + uniqueIssue.ImpactedDependencyDetails.Components = AppendComponentIfUnique(uniqueIssue.ImpactedDependencyDetails.Components, issue.ImpactedDependencyDetails.Components) + continue + } + uniqueIssues[packageKey] = &issue + } + // convert map to slice + result := make([]formats.VulnerabilityOrViolationRow, 0, len(uniqueIssues)) + for _, v := range uniqueIssues { + result = append(result, *v) + } + return result +} + +func AppendImpactPathsIfUnique(original [][]formats.ComponentRow, toAdd [][]formats.ComponentRow, multipleRoots bool) [][]formats.ComponentRow { + if multipleRoots { + return AppendImpactPathsIfUniqueForMultipleRoots(original, toAdd) + } + impactPathMap := make(map[string][]formats.ComponentRow) + for _, path := range original { + // The first node component id is the key and the value is the whole path + impactPathMap[getImpactPathKey(path)] = path + } + for _, path := range toAdd { + key := getImpactPathKey(path) + if _, exists := impactPathMap[key]; !exists { + impactPathMap[key] = path + original = append(original, path) + } + } + return original +} + +func getImpactPathKey(path []formats.ComponentRow) string { + key := getComponentKey(path[results.RootIndex]) + if len(path) == results.DirectDependencyPathLength { + key = getComponentKey(path[results.DirectDependencyIndex]) + } + return key +} + +func getComponentKey(component formats.ComponentRow) string { + return results.GetDependencyId(component.Name, component.Version) +} + +// getImpactPathKey return a key that is used as a key to identify and deduplicate impact paths. +// If an impact path length is equal to directDependencyPathLength, then the direct dependency is the key, and it's in the directDependencyIndex place. +func AppendImpactPathsIfUniqueForMultipleRoots(original [][]formats.ComponentRow, toAdd [][]formats.ComponentRow) [][]formats.ComponentRow { + for targetPathIndex, targetPath := range original { + for sourcePathIndex, sourcePath := range toAdd { + var subset []formats.ComponentRow + if len(sourcePath) <= len(targetPath) { + subset = isComponentRowIsSubset(targetPath, sourcePath) + if len(subset) != 0 { + original[targetPathIndex] = subset + } + } else { + subset = isComponentRowIsSubset(sourcePath, targetPath) + if len(subset) != 0 { + toAdd[sourcePathIndex] = subset + } + } + } + } + return AppendImpactPathsIfUnique(original, toAdd, false) +} + +// isComponentRowIsSubset checks if targetPath is a subset of sourcePath, and returns the subset if exists +func isComponentRowIsSubset(target []formats.ComponentRow, source []formats.ComponentRow) []formats.ComponentRow { + var subsetImpactPath []formats.ComponentRow + impactPathNodesMap := make(map[string]bool) + for _, node := range target { + impactPathNodesMap[getComponentKey(node)] = true + } + + for _, node := range source { + if impactPathNodesMap[getComponentKey(node)] { + subsetImpactPath = append(subsetImpactPath, node) + } + } + + if len(subsetImpactPath) == len(target) || len(subsetImpactPath) == len(source) { + return subsetImpactPath + } + return []formats.ComponentRow{} +} + +// AppendComponentIfUnique checks if the component exists in the components (not based on location) +// Removing location information for all entries as well to combine the same components from different locations +func AppendComponentIfUnique(target []formats.ComponentRow, source []formats.ComponentRow) []formats.ComponentRow { + directComponents := make(map[string]formats.ComponentRow) + for i := range target { + // Remove location information + target[i].Location = nil + // Add to the map if not exists + key := getComponentKey(target[i]) + if _, exists := directComponents[key]; !exists { + directComponents[getComponentKey(target[i])] = target[i] + } + } + for i := range source { + // Remove location information + source[i].Location = nil + // Add to the map if not exists + key := getComponentKey(source[i]) + if _, exists := directComponents[key]; !exists { + directComponents[getComponentKey(source[i])] = source[i] + } + } + result := make([]formats.ComponentRow, 0, len(directComponents)) + for _, v := range directComponents { + result = append(result, v) + } + return result +} + func sortResults(simpleJsonResults *formats.SimpleJsonResults) { if simpleJsonResults == nil { return @@ -407,67 +605,3 @@ func sortSourceCodeRow(rows []formats.SourceCodeRow) { return rows[i].Location.File > rows[j].Location.File }) } - -func convertJfrogResearchInformation(extendedInfo *services.ExtendedInformation) *formats.JfrogResearchInformation { - if extendedInfo == nil { - return nil - } - var severityReasons []formats.JfrogResearchSeverityReason - for _, severityReason := range extendedInfo.JfrogResearchSeverityReasons { - severityReasons = append(severityReasons, formats.JfrogResearchSeverityReason{ - Name: severityReason.Name, - Description: severityReason.Description, - IsPositive: severityReason.IsPositive, - }) - } - return &formats.JfrogResearchInformation{ - Summary: extendedInfo.ShortDescription, - Details: extendedInfo.FullDescription, - SeverityDetails: formats.SeverityDetails{Severity: extendedInfo.JfrogResearchSeverity}, - SeverityReasons: severityReasons, - Remediation: extendedInfo.Remediation, - } -} - -type operationalRiskViolationReadableData struct { - isEol string - cadence string - commits string - committers string - eolMessage string - riskReason string - latestVersion string - newerVersions string -} - -func getOperationalRiskViolationReadableData(violation services.Violation) *operationalRiskViolationReadableData { - isEol, cadence, commits, committers, newerVersions, latestVersion := "N/A", "N/A", "N/A", "N/A", "N/A", "N/A" - if violation.IsEol != nil { - isEol = strconv.FormatBool(*violation.IsEol) - } - if violation.Cadence != nil { - cadence = strconv.FormatFloat(*violation.Cadence, 'f', -1, 64) - } - if violation.Committers != nil { - committers = strconv.FormatInt(int64(*violation.Committers), 10) - } - if violation.Commits != nil { - commits = strconv.FormatInt(*violation.Commits, 10) - } - if violation.NewerVersions != nil { - newerVersions = strconv.FormatInt(int64(*violation.NewerVersions), 10) - } - if violation.LatestVersion != "" { - latestVersion = violation.LatestVersion - } - return &operationalRiskViolationReadableData{ - isEol: isEol, - cadence: cadence, - commits: commits, - committers: committers, - eolMessage: violation.EolMessage, - riskReason: violation.RiskReason, - latestVersion: latestVersion, - newerVersions: newerVersions, - } -} diff --git a/utils/results/conversion/summaryparser/summaryparser.go b/utils/results/conversion/summaryparser/summaryparser.go index 2ba973e4..ad6180f9 100644 --- a/utils/results/conversion/summaryparser/summaryparser.go +++ b/utils/results/conversion/summaryparser/summaryparser.go @@ -27,20 +27,20 @@ func (sc *CmdResultsSummaryConverter) Get() *formats.SummaryResults { return &formats.SummaryResults{} } // Flush the last scan - if err := sc.ParseNewScanResultsMetadata("", nil); err != nil { + if err := sc.ParseNewTargetResults("", nil); err != nil { return &formats.SummaryResults{} } return sc.current } -func (sc *CmdResultsSummaryConverter) Reset(_, _ string, entitledForJas bool) (err error) { +func (sc *CmdResultsSummaryConverter) Reset(_, _ string, entitledForJas, _ bool) (err error) { sc.current = &formats.SummaryResults{} sc.entitledForJas = entitledForJas sc.currentCveUnique = datastructures.MakeSet[string]() return } -func (sc *CmdResultsSummaryConverter) ParseNewScanResultsMetadata(target string, _ ...error) (err error) { +func (sc *CmdResultsSummaryConverter) ParseNewTargetResults(target string, _ ...error) (err error) { if sc.current == nil { return results.ConvertorResetErr } diff --git a/utils/results/conversion/tableparser/tableparser.go b/utils/results/conversion/tableparser/tableparser.go index b22f0291..bb3bbd9c 100644 --- a/utils/results/conversion/tableparser/tableparser.go +++ b/utils/results/conversion/tableparser/tableparser.go @@ -17,7 +17,7 @@ type CmdResultsTableConverter struct { } func NewCmdResultsTableConverter(pretty bool) *CmdResultsTableConverter { - return &CmdResultsTableConverter{pretty: pretty, simpleJsonConvertor: simplejsonparser.NewCmdResultsSimpleJsonConverter(pretty)} + return &CmdResultsTableConverter{pretty: pretty, simpleJsonConvertor: simplejsonparser.NewCmdResultsSimpleJsonConverter(pretty, true)} } func (tc *CmdResultsTableConverter) Get() *formats.ResultsTables { @@ -35,12 +35,12 @@ func (tc *CmdResultsTableConverter) Get() *formats.ResultsTables { } } -func (tc *CmdResultsTableConverter) Reset(multiScanId, xrayVersion string, entitledForJas bool) (err error) { - return tc.simpleJsonConvertor.Reset(multiScanId, xrayVersion, entitledForJas) +func (tc *CmdResultsTableConverter) Reset(multiScanId, xrayVersion string, entitledForJas, multipleTargets bool) (err error) { + return tc.simpleJsonConvertor.Reset(multiScanId, xrayVersion, entitledForJas, multipleTargets) } -func (tc *CmdResultsTableConverter) ParseNewScanResultsMetadata(target string, errors ...error) (err error) { - return tc.simpleJsonConvertor.ParseNewScanResultsMetadata(target, errors...) +func (tc *CmdResultsTableConverter) ParseNewTargetResults(target string, errors ...error) (err error) { + return tc.simpleJsonConvertor.ParseNewTargetResults(target, errors...) } func (tc *CmdResultsTableConverter) ParseViolations(target string, tech techutils.Technology, violations []services.Violation, applicabilityRuns ...*sarif.Run) (err error) { From 0844c65f4804ac90fdbfbec04451924e7ad7f05c Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 29 Jul 2024 12:25:42 +0300 Subject: [PATCH 47/82] fix --- utils/results/conversion/convertor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/results/conversion/convertor.go b/utils/results/conversion/convertor.go index d743cd85..e969536b 100644 --- a/utils/results/conversion/convertor.go +++ b/utils/results/conversion/convertor.go @@ -117,7 +117,7 @@ func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormat return } if targetScansResults.ScaResults != nil { - if err = c.parseScaResults(parser, targetScansResults, jasEntitled, multipleTargets); err != nil { + if err = c.parseScaResults(parser, targetScansResults, jasEntitled); err != nil { return } } From ce719c9700fe3c9f376252962085cd45e04cd3c2 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 29 Jul 2024 12:29:29 +0300 Subject: [PATCH 48/82] fix static --- .../conversion/simplejsonparser/simplejsonparser.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go index 69349d7e..f37b8015 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go @@ -416,16 +416,16 @@ func getOperationalRiskViolationReadableData(violation services.Violation) *oper // The uniqueness of the violations is determined by the GetUniqueKey function func removeScaDuplications(issues []formats.VulnerabilityOrViolationRow, multipleRoots bool) []formats.VulnerabilityOrViolationRow { var uniqueIssues = make(map[string]*formats.VulnerabilityOrViolationRow) - for _, issue := range issues { - packageKey := results.GetUniqueKey(issue.ImpactedDependencyDetails.ImpactedDependencyName, issue.ImpactedDependencyDetails.ImpactedDependencyVersion, issue.IssueId, len(issue.FixedVersions) > 0) + for i := range issues { + packageKey := results.GetUniqueKey(issues[i].ImpactedDependencyDetails.ImpactedDependencyName, issues[i].ImpactedDependencyDetails.ImpactedDependencyVersion, issues[i].IssueId, len(issues[i].FixedVersions) > 0) if uniqueIssue, exist := uniqueIssues[packageKey]; exist { // combine attributes from the same issue - uniqueIssue.FixedVersions = utils.UniqueUnion(uniqueIssue.FixedVersions, issue.FixedVersions...) - uniqueIssue.ImpactPaths = AppendImpactPathsIfUnique(uniqueIssue.ImpactPaths, issue.ImpactPaths, multipleRoots) - uniqueIssue.ImpactedDependencyDetails.Components = AppendComponentIfUnique(uniqueIssue.ImpactedDependencyDetails.Components, issue.ImpactedDependencyDetails.Components) + uniqueIssue.FixedVersions = utils.UniqueUnion(uniqueIssue.FixedVersions, issues[i].FixedVersions...) + uniqueIssue.ImpactPaths = AppendImpactPathsIfUnique(uniqueIssue.ImpactPaths, issues[i].ImpactPaths, multipleRoots) + uniqueIssue.ImpactedDependencyDetails.Components = AppendComponentIfUnique(uniqueIssue.ImpactedDependencyDetails.Components, issues[i].ImpactedDependencyDetails.Components) continue } - uniqueIssues[packageKey] = &issue + uniqueIssues[packageKey] = &issues[i] } // convert map to slice result := make([]formats.VulnerabilityOrViolationRow, 0, len(uniqueIssues)) From 3ded757ad97c8a2424203fc6bd22f57cfa7eb248 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 9 Sep 2024 13:44:20 +0300 Subject: [PATCH 49/82] merge dev --- audit_test.go | 6 +- commands/audit/audit.go | 20 +- commands/audit/audit_test.go | 58 +- commands/curation/curationaudit.go | 21 +- commands/curation/curationaudit_test.go | 2 - commands/enrich/enrich.go | 3 +- commands/scan/buildscan.go | 32 +- commands/scan/dockerscan.go | 32 +- commands/scan/scan.go | 43 +- jas/analyzermanager.go | 8 +- jas/runner/jasrunner.go | 130 +- jas/runner/jasrunner_test.go | 16 +- .../other/output/formats/audit_results.json | 1670 ----------- .../output/formats/audit_simple_json.json | 917 ------ .../other/output/formats/audit_summary.json | 36 - .../testdata/output/audit/audit_results.json | 2505 +++++++++++++++++ .../formats => output/audit}/audit_sarif.json | 633 +++-- .../output/audit/audit_simple_json.json | 1862 ++++++++++++ .../testdata/output/audit/audit_summary.json | 67 + .../jobSummary/binary_vulnerabilities.md | 0 .../jobSummary/build_scan_vulnerabilities.md | 0 .../jobSummary/docker_vulnerabilities.md | 0 .../output/jobSummary/no_violations.md | 0 .../output/jobSummary/no_vulnerabilities.md | 0 .../output/jobSummary/security_section.md | 0 .../output/jobSummary/violations.md | 0 .../jobSummary/violations_not_defined.md | 0 .../violations_not_extended_view.md | 0 tests/utils/test_utils.go | 8 +- utils/formats/sarifutils/sarifutils.go | 25 +- utils/formats/summary.go | 1 + utils/jasutils/jasutils.go | 15 + utils/results.go | 134 - utils/results/common.go | 89 +- utils/results/conversion/convertor.go | 79 +- utils/results/conversion/convertor_test.go | 44 +- .../conversion/sarifparser/sarifparser.go | 528 +++- .../sarifparser/sarifparser_test.go | 296 +- .../simplejsonparser/simplejsonparser.go | 62 +- .../simplejsonparser/simplejsonparser_test.go | 149 +- .../conversion/summaryparser/summaryparser.go | 277 +- .../summaryparser/summaryparser_test.go | 68 + .../conversion/tableparser/tableparser.go | 27 +- utils/results/output/resultwriter.go | 84 +- utils/results/output/securityJobSummary.go | 73 +- .../results/output/securityJobSummary_test.go | 95 +- utils/results/results.go | 38 +- utils/results_test.go | 46 - utils/resultstable.go | 1077 ------- utils/resultstable_test.go | 1306 --------- utils/resultwriter.go | 1163 -------- utils/resultwriter_test.go | 865 ------ utils/utils.go | 43 +- utils/utils_test.go | 66 + utils/validations/test_mocks.go | 15 +- utils/validations/test_validate_sarif.go | 52 +- utils/validations/test_validate_sca.go | 12 +- .../validations/test_validate_simple_json.go | 7 +- utils/validations/test_validate_summary.go | 44 +- utils/validations/test_validation.go | 11 + utils/xsc/analyticsmetrics.go | 11 +- utils/xsc/analyticsmetrics_test.go | 2 +- utils/xsc/configprofile_test.go | 15 +- 63 files changed, 6740 insertions(+), 8148 deletions(-) delete mode 100644 tests/testdata/other/output/formats/audit_results.json delete mode 100644 tests/testdata/other/output/formats/audit_simple_json.json delete mode 100644 tests/testdata/other/output/formats/audit_summary.json create mode 100644 tests/testdata/output/audit/audit_results.json rename tests/testdata/{other/output/formats => output/audit}/audit_sarif.json (59%) create mode 100644 tests/testdata/output/audit/audit_simple_json.json create mode 100644 tests/testdata/output/audit/audit_summary.json rename tests/testdata/{other => }/output/jobSummary/binary_vulnerabilities.md (100%) rename tests/testdata/{other => }/output/jobSummary/build_scan_vulnerabilities.md (100%) rename tests/testdata/{other => }/output/jobSummary/docker_vulnerabilities.md (100%) rename tests/testdata/{other => }/output/jobSummary/no_violations.md (100%) rename tests/testdata/{other => }/output/jobSummary/no_vulnerabilities.md (100%) rename tests/testdata/{other => }/output/jobSummary/security_section.md (100%) rename tests/testdata/{other => }/output/jobSummary/violations.md (100%) rename tests/testdata/{other => }/output/jobSummary/violations_not_defined.md (100%) rename tests/testdata/{other => }/output/jobSummary/violations_not_extended_view.md (100%) delete mode 100644 utils/results.go delete mode 100644 utils/results_test.go delete mode 100644 utils/resultstable.go delete mode 100644 utils/resultstable_test.go delete mode 100644 utils/resultwriter.go delete mode 100644 utils/resultwriter_test.go diff --git a/audit_test.go b/audit_test.go index 963d8c66..1b746335 100644 --- a/audit_test.go +++ b/audit_test.go @@ -546,7 +546,7 @@ func TestXrayAuditJasSimpleJson(t *testing.T) { Vulnerabilities: 8, Applicable: 3, - Undetermined: 1, + Undetermined: 1, NotCovered: 1, NotApplicable: 2, }) @@ -561,7 +561,7 @@ func TestXrayAuditJasSimpleJsonWithOneThread(t *testing.T) { Vulnerabilities: 8, Applicable: 3, - Undetermined: 1, + Undetermined: 1, NotCovered: 1, NotApplicable: 2, }) @@ -574,7 +574,7 @@ func TestXrayAuditJasSimpleJsonWithConfig(t *testing.T) { Vulnerabilities: 8, Applicable: 3, - Undetermined: 1, + Undetermined: 1, NotCovered: 1, NotApplicable: 2, }) diff --git a/commands/audit/audit.go b/commands/audit/audit.go index cb9621ab..344cefae 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -23,6 +23,7 @@ import ( xrayutils "github.com/jfrog/jfrog-cli-security/utils/xray" clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" + "github.com/jfrog/jfrog-client-go/utils/log" "github.com/jfrog/jfrog-client-go/xray" "github.com/jfrog/jfrog-client-go/xray/services" xscservices "github.com/jfrog/jfrog-client-go/xsc/services" @@ -268,7 +269,20 @@ func downloadAnalyzerManagerAndRunScanners(auditParallelRunner *utils.SecurityPa scan.AddError(fmt.Errorf("can't find module for path %s", scan.Target)) continue } - if err = runner.AddJasScannersTasks(auditParallelRunner, *module, scan, auditParams.DirectDependencies(), serverDetails, auditParams.thirdPartyApplicabilityScan, scanner, applicability.ApplicabilityScannerType, secrets.SecretsScannerType, auditParams.ScansToPerform(), auditParams.configProfile); err != nil { + params := runner.JasRunnerParams{ + Runner: auditParallelRunner, + ServerDetails: serverDetails, + Scanner: scanner, + Module: *module, + ConfigProfile: auditParams.configProfile, + ScansToPreform: auditParams.ScansToPerform(), + SecretsScanType: secrets.SecretsScannerType, + DirectDependencies: auditParams.DirectDependencies(), + ThirdPartyApplicabilityScan: auditParams.thirdPartyApplicabilityScan, + ApplicableScanType: applicability.ApplicabilityScannerType, + ScanResults: scan, + } + if err = runner.AddJasScannersTasks(params); err != nil { return fmt.Errorf("%s failed to run JAS scanners: %s", clientutils.GetLogMsgPrefix(threadId, false), err.Error()) } } @@ -276,13 +290,13 @@ func downloadAnalyzerManagerAndRunScanners(auditParallelRunner *utils.SecurityPa } func initCmdResults(entitledForJas bool, params *AuditParams) (cmdResults *results.SecurityCommandResults) { - cmdResults = results.NewCommandResults(params.xrayVersion, entitledForJas).SetMultiScanId(params.commonGraphScanParams.MultiScanId) + cmdResults = results.NewCommandResults(utils.SourceCode, params.xrayVersion, entitledForJas).SetMultiScanId(params.commonGraphScanParams.MultiScanId) detectScanTargets(cmdResults, params) scanInfo, err := coreutils.GetJsonIndent(cmdResults) if err != nil { return } - log.Info(fmt.Sprintf("Preforming %d scans:\n%s", len(cmdResults.Targets), scanInfo)) + log.Info(fmt.Sprintf("Preforming scans on %d targets:\n%s", len(cmdResults.Targets), scanInfo)) return } diff --git a/commands/audit/audit_test.go b/commands/audit/audit_test.go index b6bbcf2b..29d45621 100644 --- a/commands/audit/audit_test.go +++ b/commands/audit/audit_test.go @@ -1,13 +1,27 @@ package audit import ( + "os" "path/filepath" "sort" "testing" + "github.com/stretchr/testify/assert" + + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/results/conversion" "github.com/jfrog/jfrog-cli-security/utils/techutils" - "github.com/stretchr/testify/assert" + "github.com/jfrog/jfrog-cli-security/utils/validations" + "github.com/jfrog/jfrog-cli-security/utils/xray/scangraph" + + biutils "github.com/jfrog/build-info-go/utils" + + "github.com/jfrog/jfrog-cli-core/v2/common/format" + coreTests "github.com/jfrog/jfrog-cli-core/v2/utils/tests" + + clientTests "github.com/jfrog/jfrog-client-go/utils/tests" + "github.com/jfrog/jfrog-client-go/xsc/services" ) func TestDetectScansToPreform(t *testing.T) { @@ -154,7 +168,7 @@ func TestDetectScansToPreform(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - results := results.NewCommandResults("", true) + results := results.NewCommandResults(utils.SourceCode, "", true) detectScanTargets(results, test.params()) if assert.Len(t, results.Targets, len(test.expected)) { for i := range results.Targets { @@ -172,21 +186,6 @@ func TestDetectScansToPreform(t *testing.T) { cleanUp() } -package audit - -import ( - biutils "github.com/jfrog/build-info-go/utils" - "github.com/jfrog/jfrog-cli-core/v2/common/format" - coreTests "github.com/jfrog/jfrog-cli-core/v2/utils/tests" - "github.com/jfrog/jfrog-cli-security/utils" - "github.com/jfrog/jfrog-cli-security/utils/xray/scangraph" - clientTests "github.com/jfrog/jfrog-client-go/utils/tests" - "github.com/jfrog/jfrog-client-go/xsc/services" - "github.com/stretchr/testify/assert" - "os" - "path/filepath" - "testing" -) // Note: Currently, if a config profile is provided, the scan will use the profile's settings, IGNORING jfrog-apps-config if exists. func TestAuditWithConfigProfile(t *testing.T) { @@ -266,7 +265,7 @@ func TestAuditWithConfigProfile(t *testing.T) { for _, testcase := range testcases { t.Run(testcase.name, func(t *testing.T) { - mockServer, serverDetails := utils.XrayServer(t, utils.EntitlementsMinVersion) + mockServer, serverDetails := validations.XrayServer(t, utils.EntitlementsMinVersion) defer mockServer.Close() auditBasicParams := (&utils.AuditBasicParams{}). @@ -287,7 +286,6 @@ func TestAuditWithConfigProfile(t *testing.T) { XscVersion: services.ConfigProfileMinXscVersion, MultiScanId: "random-msi", }) - auditParams.SetIsRecursiveScan(true) tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t) defer createTempDirCallback() @@ -299,27 +297,15 @@ func TestAuditWithConfigProfile(t *testing.T) { chdirCallback := clientTests.ChangeDirWithCallback(t, baseWd, tempDirPath) defer chdirCallback() + auditParams.SetWorkingDirs([]string{tempDirPath}).SetIsRecursiveScan(true) auditResults, err := RunAudit(auditParams) assert.NoError(t, err) // Currently, the only supported scanners are Secrets and Sast, therefore if a config profile is utilized - all other scanners are disabled. - if testcase.expectedSastIssues > 0 { - assert.NotNil(t, auditResults.ExtendedScanResults.SastScanResults) - assert.Equal(t, testcase.expectedSastIssues, len(auditResults.ExtendedScanResults.SastScanResults[0].Results)) - } else { - assert.Nil(t, auditResults.ExtendedScanResults.SastScanResults) - } - - if testcase.expectedSecretsIssues > 0 { - assert.NotNil(t, auditResults.ExtendedScanResults.SecretsScanResults) - assert.Equal(t, testcase.expectedSecretsIssues, len(auditResults.ExtendedScanResults.SecretsScanResults[0].Results)) - } else { - assert.Nil(t, auditResults.ExtendedScanResults.SecretsScanResults) - } - - assert.Nil(t, auditResults.ScaResults) - assert.Nil(t, auditResults.ExtendedScanResults.ApplicabilityScanResults) - assert.Nil(t, auditResults.ExtendedScanResults.IacScanResults) + summary, err := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{IncludeVulnerabilities: true, HasViolationContext: true}).ConvertToSummary(auditResults) + assert.NoError(t, err) + // Validate Sast and Secrets have the expected number of issues and that Iac and Sca did not run + validations.ValidateCommandSummaryOutput(t, validations.ValidationParams{Actual: summary, ExactResultsMatch: true, Sast: testcase.expectedSastIssues, Secrets: testcase.expectedSecretsIssues, Vulnerabilities: testcase.expectedSastIssues + testcase.expectedSecretsIssues}) }) } } diff --git a/commands/curation/curationaudit.go b/commands/curation/curationaudit.go index 1dd68bfc..fffdc08c 100644 --- a/commands/curation/curationaudit.go +++ b/commands/curation/curationaudit.go @@ -27,7 +27,6 @@ import ( "github.com/jfrog/jfrog-cli-security/commands/audit" "github.com/jfrog/jfrog-cli-security/commands/audit/sca/python" - "github.com/jfrog/jfrog-cli-security/formats" "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/results/output" "github.com/jfrog/jfrog-cli-security/utils/techutils" @@ -42,22 +41,6 @@ import ( xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" "github.com/jfrog/build-info-go/build/utils/dotnet/dependencies" - - rtUtils "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" - "github.com/jfrog/jfrog-cli-core/v2/common/cliutils" - outFormat "github.com/jfrog/jfrog-cli-core/v2/common/format" - "github.com/jfrog/jfrog-cli-core/v2/common/project" - - "github.com/jfrog/jfrog-cli-core/v2/utils/config" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - - "github.com/jfrog/jfrog-cli-security/commands/audit" - "github.com/jfrog/jfrog-cli-security/commands/audit/sca/python" - "github.com/jfrog/jfrog-cli-security/formats" - "github.com/jfrog/jfrog-cli-security/utils" - "github.com/jfrog/jfrog-cli-security/utils/results/output" - "github.com/jfrog/jfrog-cli-security/utils/techutils" - "github.com/jfrog/jfrog-cli-security/utils/xray" ) const ( @@ -269,7 +252,7 @@ func (ca *CurationAuditCommand) Run() (err error) { for projectPath, packagesStatus := range results { err = errors.Join(err, printResult(ca.OutputFormat(), projectPath, packagesStatus.packagesStatus)) } - err = errors.Join(err, utils.RecordSecurityCommandSummary(utils.NewCurationSummary(convertResultsToSummary(results)))) + err = errors.Join(err, output.RecordSecurityCommandSummary(output.NewCurationSummary(convertResultsToSummary(results)))) return } @@ -785,7 +768,7 @@ func toNugetDownloadUrl(artifactoryUrl, repo, compName, compVersion string) stri // input - repo: libs-release // output - downloadUrl: /libs-release/org/apache/tomcat/embed/tomcat-embed-jasper/8.0.33/tomcat-embed-jasper-8.0.33.jar func getNugetNameScopeAndVersion(id, artiUrl, repo string) (downloadUrls []string, name, version string) { - name, version, _ = utils.SplitComponentId(id) + name, version, _ = techutils.SplitComponentId(id) downloadUrls = append(downloadUrls, toNugetDownloadUrl(artiUrl, repo, name, version)) for _, versionVariant := range dependencies.CreateAlternativeVersionForms(version) { diff --git a/commands/curation/curationaudit_test.go b/commands/curation/curationaudit_test.go index 81975ba7..4941ea7c 100644 --- a/commands/curation/curationaudit_test.go +++ b/commands/curation/curationaudit_test.go @@ -18,8 +18,6 @@ import ( "sync" "testing" - "github.com/jfrog/jfrog-cli-security/formats" - "github.com/jfrog/gofrog/datastructures" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" clienttestutils "github.com/jfrog/jfrog-client-go/utils/tests" diff --git a/commands/enrich/enrich.go b/commands/enrich/enrich.go index b596163f..ca551e89 100644 --- a/commands/enrich/enrich.go +++ b/commands/enrich/enrich.go @@ -15,6 +15,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-security/commands/enrich/enrichgraph" + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/results/output" "github.com/jfrog/jfrog-cli-security/utils/techutils" @@ -155,7 +156,7 @@ func (enrichCmd *EnrichCommand) Run() (err error) { log.Info("JFrog Xray version is:", xrayVersion) - scanResults := results.NewCommandResults(xrayVersion, false) + scanResults := results.NewCommandResults(utils.SBOM, xrayVersion, false) fileProducerConsumer := parallel.NewRunner(enrichCmd.threads, 20000, false) indexedFileProducerConsumer := parallel.NewRunner(enrichCmd.threads, 20000, false) diff --git a/commands/scan/buildscan.go b/commands/scan/buildscan.go index 07fee219..475aea9d 100644 --- a/commands/scan/buildscan.go +++ b/commands/scan/buildscan.go @@ -9,6 +9,7 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/common/build" outputFormat "github.com/jfrog/jfrog-cli-core/v2/common/format" "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/results/output" xrayutils "github.com/jfrog/jfrog-cli-security/utils/xray" @@ -112,7 +113,7 @@ func (bsc *BuildScanCommand) Run() (err error) { return err } // If failBuild flag is true and also got fail build response from Xray - if bsc.failBuild && isFailBuildResponse { + if bsc.failBuild && bsc.hasViolationContext() && isFailBuildResponse { return results.NewFailBuildError() } return @@ -144,7 +145,7 @@ func (bsc *BuildScanCommand) runBuildScanAndPrintResults(xrayManager *xray.XrayS log.Info("The scan data is available at: " + buildScanResults.MoreDetailsUrl) isFailBuildResponse = buildScanResults.FailBuild - cmdResults := results.NewCommandResults(xrayVersion, false) + cmdResults := results.NewCommandResults(utils.Build, xrayVersion, false) scanResults := cmdResults.NewScanResults(results.ScanTarget{Name: fmt.Sprintf("%s (%s)", params.BuildName, params.BuildNumber)}) scanResults.NewScaScanResults(services.ScanResponse{ Violations: buildScanResults.Violations, @@ -158,8 +159,7 @@ func (bsc *BuildScanCommand) runBuildScanAndPrintResults(xrayManager *xray.XrayS SetIncludeVulnerabilities(bsc.includeVulnerabilities). SetIncludeLicenses(false). SetIsMultipleRootProject(true). - SetPrintExtendedTable(bsc.printExtendedTable). - SetExtraMessages(nil) + SetPrintExtendedTable(bsc.printExtendedTable) if bsc.outputFormat != outputFormat.Table { // Print the violations and/or vulnerabilities as part of one JSON. @@ -170,26 +170,28 @@ func (bsc *BuildScanCommand) runBuildScanAndPrintResults(xrayManager *xray.XrayS // Print two different tables for violations and vulnerabilities (if needed) // If "No Xray Fail build policy...." error received, no need to print violations - if !noFailBuildPolicy { - if err = resultsPrinter.PrintScanResults(); err != nil { - return false, err - } - } - if bsc.includeVulnerabilities { - resultsPrinter.SetIncludeVulnerabilities(true) + if bsc.hasViolationContext() && !noFailBuildPolicy { if err = resultsPrinter.PrintScanResults(); err != nil { return false, err } } } - err = utils.RecordSecurityCommandSummary(utils.NewBuildScanSummary( - scanResults, + err = bsc.recordResults(cmdResults, params) + return +} + +func (bsc *BuildScanCommand) recordResults(cmdResults *results.SecurityCommandResults, params services.XrayBuildParams) (err error) { + var summary output.ScanCommandResultSummary + if summary, err = output.NewBuildScanSummary( + cmdResults, bsc.serverDetails, bsc.includeVulnerabilities, bsc.hasViolationContext(), params.BuildName, params.BuildNumber, - )) - return + ); err != nil { + return + } + return output.RecordSecurityCommandSummary(summary) } func (bsc *BuildScanCommand) CommandName() string { diff --git a/commands/scan/dockerscan.go b/commands/scan/dockerscan.go index 462de88d..ec619090 100644 --- a/commands/scan/dockerscan.go +++ b/commands/scan/dockerscan.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/jfrog/jfrog-cli-core/v2/common/spec" + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/results/output" "github.com/jfrog/jfrog-cli-security/utils/xray" @@ -97,29 +98,30 @@ func (dsc *DockerScanCommand) Run() (err error) { err = errorutils.CheckError(e) } }() - return dsc.ScanCommand.RunAndRecordResults(utils.DockerImage, func(scanResults *utils.Results) (err error) { + return dsc.ScanCommand.RunAndRecordResults(utils.DockerImage, func(scanResults *results.SecurityCommandResults) (err error) { if scanResults == nil { return } - if scanResults.ScaResults != nil { - for _, result := range scanResults.ScaResults { - result.Name = dsc.imageTag - } + for _, scan := range scanResults.Targets { + scan.Name = dsc.imageTag } dsc.analyticsMetricsService.UpdateGeneralEvent(dsc.analyticsMetricsService.CreateXscAnalyticsGeneralEventFinalizeFromAuditResults(scanResults)) - if err = utils.RecordSarifOutput(scanResults); err != nil { - return - } - return utils.RecordSecurityCommandSummary(utils.NewDockerScanSummary( - scanResults, - dsc.ScanCommand.serverDetails, - dsc.ScanCommand.includeVulnerabilities, - dsc.ScanCommand.hasViolationContext(), - dsc.imageTag, - )) + return dsc.recordResults(scanResults) }) } +func (dsc *DockerScanCommand) recordResults(scanResults *results.SecurityCommandResults) (err error) { + hasViolationContext := dsc.ScanCommand.hasViolationContext() + if err = output.RecordSarifOutput(scanResults, dsc.ScanCommand.includeVulnerabilities, hasViolationContext); err != nil { + return + } + var summary output.ScanCommandResultSummary + if summary, err = output.NewDockerScanSummary(scanResults, dsc.ScanCommand.serverDetails, dsc.ScanCommand.includeVulnerabilities, hasViolationContext, dsc.imageTag); err != nil { + return + } + return output.RecordSecurityCommandSummary(summary) +} + // When indexing RPM files inside the docker container, the indexer-app needs to connect to the Xray Server. // This is because RPM indexing is performed on the server side. This method therefore sets the Xray credentials as env vars to be read and used by the indexer-app. func (dsc *DockerScanCommand) setCredentialEnvsForIndexerApp() error { diff --git a/commands/scan/scan.go b/commands/scan/scan.go index 0804e400..5c8b348e 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -190,17 +190,19 @@ func (scanCmd *ScanCommand) indexFile(filePath string) (*xrayUtils.BinaryGraphNo } func (scanCmd *ScanCommand) Run() (err error) { - return scanCmd.RunAndRecordResults(utils.Binary, func(scanResults *utils.Results) (err error) { - if err = utils.RecordSarifOutput(scanResults); err != nil { - return - } - return utils.RecordSecurityCommandSummary(utils.NewBinaryScanSummary( - scanResults, - scanCmd.serverDetails, - scanCmd.includeVulnerabilities, - scanCmd.hasViolationContext(), - )) - }) + return scanCmd.RunAndRecordResults(utils.Binary, scanCmd.recordResults) +} + +func (scanCmd *ScanCommand) recordResults(scanResults *results.SecurityCommandResults) (err error) { + hasViolationContext := scanCmd.hasViolationContext() + if err = output.RecordSarifOutput(scanResults, scanCmd.includeVulnerabilities, hasViolationContext); err != nil { + return + } + var summary output.ScanCommandResultSummary + if summary, err = output.NewBinaryScanSummary(scanResults, scanCmd.serverDetails, scanCmd.includeVulnerabilities, hasViolationContext); err != nil { + return + } + return output.RecordSecurityCommandSummary(summary) } func (scanCmd *ScanCommand) RunAndRecordResults(cmdType utils.CommandType, recordResFunc func(scanResults *results.SecurityCommandResults) error) (err error) { @@ -223,9 +225,9 @@ func (scanCmd *ScanCommand) RunAndRecordResults(cmdType utils.CommandType, recor return err } - cmdResults := results.NewCommandResults(cmdTypexrayVersion, entitledForJas && scanCmd.commandSupportsJAS) + cmdResults := results.NewCommandResults(cmdType, xrayVersion, entitledForJas && scanCmd.commandSupportsJAS) if scanCmd.analyticsMetricsService != nil { - scanResults.MultiScanId = scanCmd.analyticsMetricsService.GetMsi() + cmdResults.SetMultiScanId(scanCmd.analyticsMetricsService.GetMsi()) } errGroup := new(errgroup.Group) @@ -308,7 +310,7 @@ func (scanCmd *ScanCommand) RunAndRecordResults(cmdType utils.CommandType, recor SetIncludeVulnerabilities(scanCmd.includeVulnerabilities). SetIncludeLicenses(scanCmd.includeLicenses). SetPrintExtendedTable(scanCmd.printExtendedTable). - SetIsMultipleRootProject(scanResults.IsMultipleProject()). + SetIsMultipleRootProject(cmdResults.HasMultipleTargets()). PrintScanResults(); err != nil { return } @@ -427,7 +429,18 @@ func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, cmdResults if err != nil { return err } - err = runner.AddJasScannersTasks(jasFileProducerConsumer, module, targetResults, directDepsListFromVulnerabilities(*graphScanResults), scanCmd.serverDetails, false, scanner, applicability.ApplicabilityDockerScanScanType, secrets.SecretsScannerDockerScanType, utils.GetAllSupportedScans()) + jasParams := runner.JasRunnerParams{ + Runner: jasFileProducerConsumer, + ServerDetails: scanCmd.serverDetails, + Scanner: scanner, + Module: module, + ScansToPreform: utils.GetAllSupportedScans(), + SecretsScanType: secrets.SecretsScannerDockerScanType, + DirectDependencies: directDepsListFromVulnerabilities(*graphScanResults), + ApplicableScanType: applicability.ApplicabilityDockerScanScanType, + ScanResults: targetResults, + } + err = runner.AddJasScannersTasks(jasParams) if err != nil { log.Error(fmt.Sprintf("%s jas scanning failed with error: %s", clientutils.GetLogMsgPrefix(scanThreadId, false), err.Error())) targetResults.AddError(err) diff --git a/jas/analyzermanager.go b/jas/analyzermanager.go index c4e60a3b..680f4d70 100644 --- a/jas/analyzermanager.go +++ b/jas/analyzermanager.go @@ -78,7 +78,7 @@ func (am *AnalyzerManager) ExecWithOutputFile(configFile, scanCommand, workingDi cmd.Env = utils.ToCommandEnvVars(envVars) cmd.Dir = workingDir output, err := cmd.CombinedOutput() - if isCI() || err != nil { + if utils.IsCI() || err != nil { if len(output) > 0 { log.Debug(fmt.Sprintf("%s %q output: %s", workingDir, strings.Join(cmd.Args, " "), string(output))) } @@ -134,10 +134,6 @@ func GetAnalyzerManagerExecutableName() string { return analyzerManager } -func isCI() bool { - return strings.ToLower(os.Getenv(coreutils.CI)) == "true" -} - func GetAnalyzerManagerEnvVariables(serverDetails *config.ServerDetails) (envVars map[string]string, err error) { envVars = map[string]string{ jfUserEnvVariable: serverDetails.User, @@ -145,7 +141,7 @@ func GetAnalyzerManagerEnvVariables(serverDetails *config.ServerDetails) (envVar jfPlatformUrlEnvVariable: serverDetails.Url, jfTokenEnvVariable: serverDetails.AccessToken, } - if !isCI() { + if !utils.IsCI() { analyzerManagerLogFolder, err := coreutils.CreateDirInJfrogHome(filepath.Join(coreutils.JfrogLogsDirName, analyzerManagerLogDirName)) if err != nil { return nil, err diff --git a/jas/runner/jasrunner.go b/jas/runner/jasrunner.go index c4ed02ae..fb34cf85 100644 --- a/jas/runner/jasrunner.go +++ b/jas/runner/jasrunner.go @@ -19,88 +19,94 @@ import ( "golang.org/x/exp/slices" ) -func AddJasScannersTasks(securityParallelRunner *utils.SecurityParallelRunner, module jfrogappsconfig.Module, scanResults *results.TargetResults, directDependencies *[]string, - serverDetails *config.ServerDetails, thirdPartyApplicabilityScan bool, scanner *jas.JasScanner, scanType applicability.ApplicabilityScanType, - secretsScanType secrets.SecretsScanType, scansToPreform []utils.SubScanType, configProfile *services.ConfigProfile) (err error) { - if serverDetails == nil || len(serverDetails.Url) == 0 { +type JasRunnerParams struct { + Runner *utils.SecurityParallelRunner + ServerDetails *config.ServerDetails + Scanner *jas.JasScanner + + Module jfrogappsconfig.Module + ConfigProfile *services.ConfigProfile + + ScansToPreform []utils.SubScanType + + SecretsScanType secrets.SecretsScanType + + DirectDependencies *[]string + ThirdPartyApplicabilityScan bool + ApplicableScanType applicability.ApplicabilityScanType + + ScanResults *results.TargetResults +} + +func AddJasScannersTasks(params JasRunnerParams) (err error) { + if params.ServerDetails == nil || len(params.ServerDetails.Url) == 0 { log.Warn("To include 'Advanced Security' scan as part of the audit output, please run the 'jf c add' command before running this command.") return } // For docker scan we support only secrets and contextual scans. runAllScanners := false - if scanType == applicability.ApplicabilityScannerType || secretsScanType == secrets.SecretsScannerType { + if params.ApplicableScanType == applicability.ApplicabilityScannerType || params.SecretsScanType == secrets.SecretsScannerType { runAllScanners = true } - // Set environments variables for analytics in analyzers manager. - if len(scansToPreform) > 0 && !slices.Contains(scansToPreform, utils.ContextualAnalysisScan) { - log.Debug("Skipping contextual analysis scan as requested by input...") - return err + if err = addJasScanTaskForModuleIfNeeded(params, utils.ContextualAnalysisScan, runContextualScan(params.Runner, params.Scanner, params.ScanResults, params.Module, params.DirectDependencies, params.ThirdPartyApplicabilityScan, params.ApplicableScanType)); err != nil { + return } - if err = addModuleJasScanTask(module, jasutils.Applicability, securityParallelRunner, runContextualScan(securityParallelRunner, scanner, scanResults, module, directDependencies, thirdPartyApplicabilityScan, scanType), scanResults); err != nil { + if params.ThirdPartyApplicabilityScan { + // Don't execute other scanners when scanning third party dependencies. return } - // Don't execute other scanners when scanning third party dependencies. - // Currently, if config profile exists, the only possible scanners to run are: Secrets, Sast - if !thirdPartyApplicabilityScan { - for _, module := range scanner.JFrogAppsConfig.Modules { - if len(scansToPreform) > 0 && !slices.Contains(scansToPreform, utils.SecretsScan) { - log.Debug("Skipping secrets scan as requested by input...") - } else if configProfile != nil { - // This code section is related to CentralizedConfig integration in CI Next. - log.Debug(fmt.Sprintf("Using config profile '%s' to determine whether to run secrets scan...", configProfile.ProfileName)) - if configProfile.Modules[0].ScanConfig.SecretsScannerConfig.EnableSecretsScan { - err = addModuleJasScanTask(jfrogappsconfig.Module{}, jasutils.Secrets, securityParallelRunner, runSecretsScan(securityParallelRunner, scanner, scanResults.ExtendedScanResults, module, secretsScanType), errHandlerFunc) - } else { - log.Debug(fmt.Sprintf("Skipping secrets scan as requested by '%s' config profile...", configProfile.ProfileName)) - } - } else if err = addModuleJasScanTask(module, jasutils.Secrets, securityParallelRunner, runSecretsScan(securityParallelRunner, scanner, scanResults.ExtendedScanResults, module, secretsScanType), errHandlerFunc); err != nil { - return - } - if runAllScanners { - if configProfile == nil { - if len(scansToPreform) > 0 && !slices.Contains(scansToPreform, utils.IacScan) { - log.Debug("Skipping Iac scan as requested by input...") - } else if err = addModuleJasScanTask(module, jasutils.IaC, securityParallelRunner, runIacScan(securityParallelRunner, scanner, scanResults.ExtendedScanResults, module), errHandlerFunc); err != nil { - return - } - } - if len(scansToPreform) > 0 && !slices.Contains(scansToPreform, utils.SastScan) { - log.Debug("Skipping Sast scan as requested by input...") - } else if configProfile != nil { - log.Debug(fmt.Sprintf("Using config profile '%s' to determine whether to run Sast scan...", configProfile.ProfileName)) - if configProfile.Modules[0].ScanConfig.SastScannerConfig.EnableSastScan { - err = addModuleJasScanTask(jfrogappsconfig.Module{}, jasutils.Sast, securityParallelRunner, runSastScan(securityParallelRunner, scanner, scanResults.ExtendedScanResults, module), errHandlerFunc) - } else { - log.Debug(fmt.Sprintf("Skipping Sast scan as requested by '%s' config profile...", configProfile.ProfileName)) - } - } else if err = addModuleJasScanTask(module, jasutils.Sast, securityParallelRunner, runSastScan(securityParallelRunner, scanner, scanResults.ExtendedScanResults, module), errHandlerFunc); err != nil { - return - } - } - } + if err = addJasScanTaskForModuleIfNeeded(params, utils.SecretsScan, runSecretsScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module, params.SecretsScanType)); err != nil { + return } - - if configProfile != nil { - log.Debug("Config profile is in use. Skipping Contextual Analysis scan as it is not currently supported with a config profile...") + if !runAllScanners { return } + if err = addJasScanTaskForModuleIfNeeded(params, utils.IacScan, runIacScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module)); err != nil { + return + } + return addJasScanTaskForModuleIfNeeded(params, utils.SastScan, runSastScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module)) +} - if len(scansToPreform) > 0 && !slices.Contains(scansToPreform, utils.ContextualAnalysisScan) { - log.Debug("Skipping contextual analysis scan as requested by input...") - return err +func addJasScanTaskForModuleIfNeeded(params JasRunnerParams, subScan utils.SubScanType, task parallel.TaskFunc) (err error) { + jasType := jasutils.SubScanTypeToJasScanType(subScan) + if jasType == "" { + return fmt.Errorf("failed to determine Jas scan type for %s", subScan) } - for _, module := range scanner.JFrogAppsConfig.Modules { - if err = addModuleJasScanTask(module, jasutils.Applicability, securityParallelRunner, runContextualScan(securityParallelRunner, scanner, scanResults, module, directDependencies, thirdPartyApplicabilityScan, scanType), errHandlerFunc); err != nil { + if len(params.ScansToPreform) > 0 && !slices.Contains(params.ScansToPreform, subScan) { + log.Debug(fmt.Sprintf("Skipping %s scan as requested by input...", subScan)) + } + if params.ConfigProfile != nil { + // This code section is related to CentralizedConfig integration in CI Next. + log.Debug(fmt.Sprintf("Using config profile '%s' to determine whether to run %s scan...", params.ConfigProfile.ProfileName, jasType)) + // Currently, if config profile exists, the only possible scanners to run are: Secrets, Sast + enabled := false + switch jasType { + case jasutils.Secrets: + enabled = params.ConfigProfile.Modules[0].ScanConfig.SecretsScannerConfig.EnableSecretsScan + case jasutils.Sast: + enabled = params.ConfigProfile.Modules[0].ScanConfig.SastScannerConfig.EnableSastScan + case jasutils.IaC: + log.Debug("Skipping Iac scan as it is not currently supported with a config profile...") + return + case jasutils.Applicability: + log.Debug("Skipping Contextual Analysis scan as it is not currently supported with a config profile...") return } + if enabled { + err = addModuleJasScanTask(jasType, params.Runner, task, params.ScanResults) + } else { + log.Debug(fmt.Sprintf("Skipping %s scan as requested by '%s' config profile...", jasType, params.ConfigProfile.ProfileName)) + } + return } - return err -} - -func addModuleJasScanTask(module jfrogappsconfig.Module, scanType jasutils.JasScanType, securityParallelRunner *utils.SecurityParallelRunner, task parallel.TaskFunc, scanResults *results.TargetResults) (err error) { - if jas.ShouldSkipScanner(module, scanType) { + if jas.ShouldSkipScanner(params.Module, jasType) { + log.Debug(fmt.Sprintf("Skipping %s scan as requested by local module config...", subScan)) return } + return addModuleJasScanTask(jasType, params.Runner, task, params.ScanResults) +} + +func addModuleJasScanTask(scanType jasutils.JasScanType, securityParallelRunner *utils.SecurityParallelRunner, task parallel.TaskFunc, scanResults *results.TargetResults) (err error) { securityParallelRunner.JasScannersWg.Add(1) if _, err = securityParallelRunner.Runner.AddTaskWithError(task, func(err error) { scanResults.AddError(err) diff --git a/jas/runner/jasrunner_test.go b/jas/runner/jasrunner_test.go index 3e60fb7a..f59316d7 100644 --- a/jas/runner/jasrunner_test.go +++ b/jas/runner/jasrunner_test.go @@ -4,7 +4,6 @@ import ( "os" "testing" - jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" "github.com/jfrog/jfrog-cli-core/v2/common/cliutils" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" @@ -36,14 +35,25 @@ func TestGetExtendedScanResults_AnalyzerManagerDoesntExist(t *testing.T) { func TestGetExtendedScanResults_ServerNotValid(t *testing.T) { securityParallelRunnerForTest := utils.CreateSecurityParallelRunner(cliutils.Threads) - targetResults := results.NewCommandResults("", true).NewScanResults(results.ScanTarget{Target: "target", Technology: techutils.Pip}) + targetResults := results.NewCommandResults(utils.SourceCode, "", true).NewScanResults(results.ScanTarget{Target: "target", Technology: techutils.Pip}) scanner := &jas.JasScanner{} jasScanner, err := jas.CreateJasScanner(scanner, &jas.FakeServerDetails, jas.GetAnalyzerManagerXscEnvVars("", targetResults.GetTechnologies()...)) assert.NoError(t, err) targetResults.NewScaScanResults(jas.FakeBasicXrayResults[0]) - err = AddJasScannersTasks(securityParallelRunnerForTest, jfrogappsconfig.Module{}, targetResults, &[]string{"issueId_1_direct_dependency", "issueId_2_direct_dependency"}, nil, false, jasScanner, applicability.ApplicabilityScannerType, secrets.SecretsScannerType, utils.GetAllSupportedScans(), nil) + testParams := JasRunnerParams{ + Runner: securityParallelRunnerForTest, + Scanner: jasScanner, + ScanResults: targetResults, + + ScansToPreform: utils.GetAllSupportedScans(), + ApplicableScanType: applicability.ApplicabilityScannerType, + SecretsScanType: secrets.SecretsScannerType, + + DirectDependencies: &[]string{"issueId_1_direct_dependency", "issueId_2_direct_dependency"}, + } + err = AddJasScannersTasks(testParams) assert.NoError(t, err) } diff --git a/tests/testdata/other/output/formats/audit_results.json b/tests/testdata/other/output/formats/audit_results.json deleted file mode 100644 index 1f15f8c8..00000000 --- a/tests/testdata/other/output/formats/audit_results.json +++ /dev/null @@ -1,1670 +0,0 @@ -{ - "xray_version": "3.98.2", - "jas_entitled": true, - "multi_scan_id": "7d5e4733-3f93-11ef-8147-e610d09d7daa", - "targets": [ - { - "target": "/Users/user/ejs-frog-demo", - "technology": "npm", - "sca_scans": { - "is_multiple_root_project": false, - "descriptors": [ - "/Users/user/ejs-frog-demo/package.json" - ], - "xray_scan": [ - { - "scan_id": "3d90ec4b-cf33-4846-6831-4bf9576f2235", - "vulnerabilities": [ - { - "cves": [ - { - "cve": "CVE-2019-1010266", - "cvss_v2_score": "4.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:S/C:N/I:N/A:P", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-400", - "CWE-770" - ], - "cwe_details": { - "CWE-400": { - "name": "Uncontrolled Resource Consumption", - "description": "The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources." - }, - "CWE-770": { - "name": "Allocation of Resources Without Limits or Throttling", - "description": "The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor." - } - } - } - ], - "summary": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", - "severity": "Medium", - "components": { - "npm://lodash:4.17.0": { - "fixed_versions": [ - "[4.17.11]" - ], - "impact_paths": [ - [ - { - "component_id": "npm://froghome:1.0.0" - }, - { - "component_id": "npm://lodash:4.17.0" - } - ] - ] - } - }, - "issue_id": "XRAY-85049" - }, - { - "cves": [ - { - "cve": "CVE-2020-28500", - "cvss_v2_score": "5.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P", - "cvss_v3_score": "5.3", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", - "cwe": [ - "CWE-400", - "CWE-1333", - "NVD-CWE-Other" - ], - "cwe_details": { - "CWE-1333": { - "name": "Inefficient Regular Expression Complexity", - "description": "The product uses a regular expression with an inefficient, possibly exponential worst-case computational complexity that consumes excessive CPU cycles." - }, - "CWE-400": { - "name": "Uncontrolled Resource Consumption", - "description": "The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources." - } - } - } - ], - "summary": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", - "severity": "Medium", - "components": { - "npm://lodash:4.17.0": { - "fixed_versions": [ - "[4.17.21]" - ], - "impact_paths": [ - [ - { - "component_id": "npm://froghome:1.0.0" - }, - { - "component_id": "npm://lodash:4.17.0" - } - ] - ] - } - }, - "issue_id": "XRAY-140562", - "extended_information": { - "short_description": "ReDoS in lodash could lead to a denial of service when handling untrusted strings.", - "full_description": "JavaScript-based applications that use [lodash](https://github.com/lodash/lodash) and specifically the [_.toNumber](https://lodash.com/docs/4.17.15#toNumber), [_.trim](https://lodash.com/docs/4.17.15#trim) and [_.trimEnd](https://lodash.com/docs/4.17.15#trimEnd) functions, could be vulnerable to DoS (Denial of Service) through a faulty regular expression that introduces a ReDoS (Regular Expression DoS) vulnerability. This vulnerability is only triggered if untrusted user input flows into these vulnerable functions and the attacker can supply arbitrary long strings (over 50kB) that contain whitespaces. \n\nOn a modern Core i7-based system, calling the vulnerable functions with a 50kB string could take between 2 to 3 seconds to execute and 4.5 minutes for a longer 500kB string. The fix improved the regular expression performance so it took only a few milliseconds on the same Core i7-based system. This vulnerability is easily exploitable as all is required is to build a string that triggers it as can be seen in this PoC reproducing code - \n\n```js\nvar untrusted_user_input_50k = \"a\" + ' '.repeat(50000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_50k); // should take a few seconds to run\nvar untrusted_user_input_500k = \"a\" + ' '.repeat(500000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_500k); // should take a few minutes to run\n```", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "Public exploit demonstrated ReDoS" - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "Exploitation depends on parsing user input by the `.toNumber`, `.trim` or `.trimEnd` `lodash` functions, and requires the input to contain whitespaces and be very long (over 50KB)", - "is_positive": true - } - ], - "remediation": "##### Deployment mitigations\n\nTrim untrusted strings based on size before providing it to the vulnerable functions by using the `substring` function to with a fixed maximum size like so - ```js untrusted_user_input.substring(0, max_string_size_less_than_50kB); ```" - } - }, - { - "cves": [ - { - "cve": "CVE-2018-3721", - "cvss_v2_score": "4.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:S/C:N/I:P/A:N", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N", - "cwe": [ - "CWE-1321", - "CWE-471" - ], - "cwe_details": { - "CWE-1321": { - "name": "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')", - "description": "The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype." - }, - "CWE-471": { - "name": "Modification of Assumed-Immutable Data (MAID)", - "description": "The product does not properly protect an assumed-immutable element from being modified by an attacker." - } - } - } - ], - "summary": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", - "severity": "Medium", - "components": { - "npm://lodash:4.17.0": { - "fixed_versions": [ - "[4.17.5]" - ], - "impact_paths": [ - [ - { - "component_id": "npm://froghome:1.0.0" - }, - { - "component_id": "npm://lodash:4.17.0" - } - ] - ] - } - }, - "issue_id": "XRAY-72918" - }, - { - "cves": [ - { - "cve": "CVE-2020-8203", - "cvss_v2_score": "5.8", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:P/A:P", - "cvss_v3_score": "7.4", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:H", - "cwe": [ - "CWE-770", - "CWE-1321" - ], - "cwe_details": { - "CWE-1321": { - "name": "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')", - "description": "The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype." - }, - "CWE-770": { - "name": "Allocation of Resources Without Limits or Throttling", - "description": "The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor." - } - } - } - ], - "summary": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", - "severity": "High", - "components": { - "npm://lodash:4.17.0": { - "fixed_versions": [ - "[4.17.19]" - ], - "impact_paths": [ - [ - { - "component_id": "npm://froghome:1.0.0" - }, - { - "component_id": "npm://lodash:4.17.0" - } - ] - ] - } - }, - "issue_id": "XRAY-114089", - "extended_information": { - "short_description": "Prototype pollution in lodash object merging and zipping functions leads to code injection.", - "full_description": "[lodash](https://lodash.com/) is a JavaScript library which provides utility functions for common programming tasks.\n\nJavaScript frontend and Node.js-based backend applications that merge or zip objects using the lodash functions `mergeWith`, `merge` and `zipObjectDeep` are vulnerable to [prototype pollution](https://medium.com/node-modules/what-is-prototype-pollution-and-why-is-it-such-a-big-deal-2dd8d89a93c) if one or more of the objects it receives as arguments are obtained from user input. \nAn attacker controlling this input given to the vulnerable functions can inject properties to JavaScript special objects such as [Object.prototype](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes) from which all JavaScript objects inherit properties and methods. Any change on `Object.prototype` properties will then propagate through the prototype chain inheritance to all of the objects in a JavaScript application. This in turn would allow an attacker to add new properties or modify existing properties which will have application specific implications that could lead to DoS (denial of service), authentication bypass, privilege escalation and even RCE (remote code execution) in [some cases](https://youtu.be/LUsiFV3dsK8?t=1152). \nAs an example for privilege escalation, consider a JavaScript application that has a `user` object which has a Boolean property of `user.isAdmin` which is used to decide which actions the user may take. If an attacker can modify or add the `isAdmin` property through prototype pollution, it can escalate the privileges of its own user to those of an admin. \nAs exploitation is usually application specific, successful exploitation is much more likely if an attacker have access to the JavaScript application code. As such, frontend applications are more vulnerable to this vulnerability than Node.js backend applications.", - "jfrog_research_severity": "Critical", - "jfrog_research_severity_reasons": [ - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "is_positive": true - }, - { - "name": "The issue can be exploited by attackers over the network" - }, - { - "name": "The issue is trivial to exploit and does not require a published writeup or PoC" - } - ], - "remediation": "##### Deployment mitigations\n\nAs general guidelines against prototype pollution, first consider not merging objects originating from user input or using a Map structure instead of an object. If merging objects is needed, look into creating objects without a prototype with `Object.create(null)` or into freezing `Object.prototype` with `Object.freeze()`. Finally, it is always best to perform input validation with a a [JSON schema validator](https://github.com/ajv-validator/ajv), which could mitigate this issue entirely in many cases." - } - }, - { - "cves": [ - { - "cve": "CVE-2021-23337", - "cvss_v2_score": "6.5", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:S/C:P/I:P/A:P", - "cvss_v3_score": "7.2", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-77", - "CWE-94" - ], - "cwe_details": { - "CWE-77": { - "name": "Improper Neutralization of Special Elements used in a Command ('Command Injection')", - "description": "The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "16" - } - ] - }, - "CWE-94": { - "name": "Improper Control of Generation of Code ('Code Injection')", - "description": "The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "23" - } - ] - } - } - } - ], - "summary": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", - "severity": "High", - "components": { - "npm://lodash:4.17.0": { - "fixed_versions": [ - "[4.17.21]" - ], - "impact_paths": [ - [ - { - "component_id": "npm://froghome:1.0.0" - }, - { - "component_id": "npm://lodash:4.17.0" - } - ] - ] - } - }, - "issue_id": "XRAY-140575", - "extended_information": { - "short_description": "Improper sanitization in the lodash template function leads to JavaScript code injection through the options argument.", - "full_description": "JavaScript-based applications (both frontend and backend) that use the [template function](https://lodash.com/docs/4.17.15#template) -`_.template([string=''], [options={}])` from the [lodash](https://lodash.com/) utility library and provide the `options` argument (specifically the `variable` option) from untrusted user input, are vulnerable to JavaScript code injection. This issue can be easily exploited, and an exploitation example is [publicly available](https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c#diff-a561630bb56b82342bc66697aee2ad96efddcbc9d150665abd6fb7ecb7c0ab2fR22303) in the fix tests that was introduced in version 4.17.21 - \n```js\nlodash.template('', { variable: '){console.log(process.env)}; with(obj' })()\n```", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "It is highly unlikely that a JS program will accept arbitrary remote input into the template's `options` argument", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker must find remote input that propagates into the `options` argument of a `template` call", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Leads to remote code execution through JS code injection" - }, - { - "name": "The issue has an exploit published", - "description": "Published exploit demonstrates arbitrary JS code execution" - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2018-16487", - "cvss_v2_score": "6.8", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:P/I:P/A:P", - "cvss_v3_score": "5.6", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L", - "cwe": [ - "CWE-400", - "NVD-CWE-noinfo" - ], - "cwe_details": { - "CWE-400": { - "name": "Uncontrolled Resource Consumption", - "description": "The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources." - } - } - } - ], - "summary": "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": "Medium", - "components": { - "npm://lodash:4.17.0": { - "fixed_versions": [ - "[4.17.11]" - ], - "impact_paths": [ - [ - { - "component_id": "npm://froghome:1.0.0" - }, - { - "component_id": "npm://lodash:4.17.0" - } - ] - ] - } - }, - "issue_id": "XRAY-75300", - "extended_information": { - "short_description": "Insufficient input validation in the Lodash library leads to prototype pollution.", - "full_description": "The [Lodash](https://lodash.com/) library is an open-source JavaScript project that simplifies operations on string, arrays, numbers, and other objects. It is widely used in connected devices. \n\nThe `merge`, `mergeWith`, and `defaultsDeep` methods in Lodash are vulnerable to [prototype pollution](https://shieldfy.io/security-wiki/prototype-pollution/introduction-to-prototype-pollution/). Attackers can exploit this vulnerability by specifying a crafted `sources` parameter to any of these methods, which can modify the prototype properties of the `Object`, `Function`, `Array`, `String`, `Number`, and `Boolean` objects. A public [exploit](https://hackerone.com/reports/380873) exists which performs the prototype pollution with an arbitrary key and value.\n\nThe library implementation has a bug in the `safeGet()` function in the `lodash.js` module that allows for adding or modifying `prototype` properties of various objects. The official [solution](https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad) fixes the bug by explicitly forbidding the addition or modification of `prototype` properties.\n\nA related CVE (CVE-2018-3721) covers the same issue prior to Lodash version 4.17.5, but the fix for that was incomplete.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "An attacker must find remote input that propagates into one of the following methods - \n* `merge` - 2nd argument\n* `mergeWith` - 2nd argument\n* `defaultsDeep` - 2nd argument", - "is_positive": true - }, - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "A public PoC demonstrated exploitation by injecting an attacker controlled key and value into the prototype" - } - ], - "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." - } - }, - { - "cves": [ - { - "cve": "CVE-2019-10744", - "cvss_v2_score": "6.4", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:P/A:P", - "cvss_v3_score": "9.1", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H", - "cwe": [ - "CWE-1321", - "CWE-20" - ], - "cwe_details": { - "CWE-1321": { - "name": "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')", - "description": "The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype." - }, - "CWE-20": { - "name": "Improper Input Validation", - "description": "The product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "6" - } - ] - } - } - } - ], - "summary": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", - "severity": "Critical", - "components": { - "npm://lodash:4.17.0": { - "fixed_versions": [ - "[4.17.12]" - ], - "impact_paths": [ - [ - { - "component_id": "npm://froghome:1.0.0" - }, - { - "component_id": "npm://lodash:4.17.0" - } - ] - ] - } - }, - "issue_id": "XRAY-85679", - "extended_information": { - "short_description": "Insufficient input validation in lodash defaultsDeep() leads to prototype pollution.", - "full_description": "[lodash](https://www.npmjs.com/package/lodash) is a modern JavaScript utility library delivering modularity, performance, \u0026 extras.\n\nThe function `defaultsDeep` was found to be vulnerable to prototype pollution, when accepting arbitrary source objects from untrusted input\n\nExample of code vulnerable to this issue - \n```js\nconst lodash = require('lodash'); \nconst evilsrc = {constructor: {prototype: {evilkey: \"evilvalue\"}}};\nlodash.defaultsDeep({}, evilsrc)\n```", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "A public PoC demonstrates exploitation of this issue" - }, - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "An attacker must find remote input that propagates into the `defaultsDeep` method (2nd arg)", - "is_positive": true - } - ], - "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." - } - }, - { - "cves": [ - { - "cve": "CVE-2024-29041", - "cvss_v3_score": "6.1", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N", - "cwe": [ - "CWE-601", - "CWE-1286" - ], - "cwe_details": { - "CWE-1286": { - "name": "Improper Validation of Syntactic Correctness of Input", - "description": "The product receives input that is expected to be well-formed - i.e., to comply with a certain syntax - but it does not validate or incorrectly validates that the input complies with the syntax." - }, - "CWE-601": { - "name": "URL Redirection to Untrusted Site ('Open Redirect')", - "description": "A web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a Redirect. This simplifies phishing attacks." - } - } - } - ], - "summary": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", - "severity": "Medium", - "components": { - "npm://express:4.18.2": { - "fixed_versions": [ - "[4.19.2]", - "[5.0.0-beta.3]" - ], - "impact_paths": [ - [ - { - "component_id": "npm://froghome:1.0.0" - }, - { - "component_id": "npm://express:4.18.2" - } - ] - ] - } - }, - "issue_id": "XRAY-594935" - }, - { - "cves": [ - { - "cve": "CVE-2024-39249" - } - ], - "summary": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", - "severity": "Unknown", - "components": { - "npm://async:3.2.4": { - "impact_paths": [ - [ - { - "component_id": "npm://froghome:1.0.0" - }, - { - "component_id": "npm://ejs:3.1.6" - }, - { - "component_id": "npm://jake:10.8.7" - }, - { - "component_id": "npm://async:3.2.4" - } - ] - ] - } - }, - "issue_id": "XRAY-609848", - "extended_information": { - "short_description": "ReDoS in Async may lead to denial of service while parsing malformed source code.", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The reported CVSS does not reflect the severity of the vulnerability.", - "is_positive": true - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "To exploit this issue an attacker must change the source code of the application. In cases where an attacker can already modify (or fully control) the source code, the attacker can immediately achieve arbitrary code execution - thus this issue has almost no security impact.", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "A proof-of-concept has been published in the advisory." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The issue requires the use of the `async.autoInject` function to be vulnerable.", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2024-33883", - "cwe": [ - "CWE-1321" - ], - "cwe_details": { - "CWE-1321": { - "name": "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')", - "description": "The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype." - } - } - } - ], - "summary": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", - "severity": "Medium", - "components": { - "npm://ejs:3.1.6": { - "fixed_versions": [ - "[3.1.10]" - ], - "impact_paths": [ - [ - { - "component_id": "npm://froghome:1.0.0" - }, - { - "component_id": "npm://ejs:3.1.6" - } - ] - ] - } - }, - "issue_id": "XRAY-599735", - "extended_information": { - "short_description": "Insufficient input validation in EJS may lead to prototype pollution.", - "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as `EJS`, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nA prototype pollution gadget within the EJS template engine could potentially be leveraged by attackers to achieve remote code execution or DoS via prototype pollution.\n\n```\nfunction Template(text, opts) {\n opts = opts || utils.createNullProtoObjWherePossible();\n```\n\nWhen checking for the presence of a property within an object variable, the lookup scope isn't explicitly defined. In JavaScript, the absence of a defined lookup scope prompts a search up to the root prototype (`Object.prototype`). This could potentially be under the control of an attacker if another prototype pollution vulnerability is present within the application.\n\nIf the application server is using the EJS as the backend template engine, and there is another prototype pollution vulnerability in the application, then the attacker could leverage the found gadgets in the EJS template engine to escalate the prototype pollution to remote code execution or DoS.\n\nThe following code will execute a command on the server by polluting `opts.escapeFunction`:\n \n```\nconst express = require('express');\nconst app = express();\nconst port = 8008;\nconst ejs = require('ejs');\n\n// Set EJS as the view engine\napp.set('view engine', 'ejs');\n\napp.get('/', (req, res) =\u003e {\n \n const data = {title: 'Welcome', message: 'Hello'};\n\n // Sample EJS template string\n const templateString = `\u003chtml\u003e\u003chead\u003e\u003ctitle\u003e\u003c%= title %\u003e\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003ch1\u003e\u003c%= message %\u003e\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e`;\n\n const { exec } = require('child_process');\n\n function myFunc() {\n exec('bash -c \"echo 123\"', (error, stdout, stderr) =\u003e {\n if (error) {\n console.error(`exec error: ${error}`);\n return;\n }\n if (stderr){\n console.log(`stderr : ${stderr}`);\n return;\n }\n // Handle success\n console.log(`Command executed successfully. Output: ${stdout}`);\n });\n }\n\n const options = {client:false};\n\n Object.prototype.escapeFunction = myFunc;\n \n const compiledTemplate = ejs.compile(templateString, options);\n const renderedHtml = compiledTemplate(data);\n res.send(renderedHtml);\n});\n\n// Start the server\napp.listen(port, () =\u003e {\n console.log(`Server is running on http://localhost:${port}`);\n});\n```", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "Attackers can only leverage this vulnerability when the application server is using the EJS as the backend template engine. Moreover, there must be a second prototype pollution vulnerability in the application.", - "is_positive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "CVSS does not take into account the unlikely prerequisites necessary for exploitation.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "A prototype pollution attack allows the attacker to inject new properties into all JavaScript objects.\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable." - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-29827", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-74" - ], - "cwe_details": { - "CWE-74": { - "name": "Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')", - "description": "The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component." - } - } - } - ], - "summary": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", - "severity": "Critical", - "components": { - "npm://ejs:3.1.6": { - "impact_paths": [ - [ - { - "component_id": "npm://froghome:1.0.0" - }, - { - "component_id": "npm://ejs:3.1.6" - } - ] - ] - } - }, - "issue_id": "XRAY-520200", - "extended_information": { - "short_description": "Insufficient input validation can lead to template injection in ejs when attackers can control both the rendered template and rendering options.", - "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to bypass ejs' template injection restrictions, by abusing the `closeDelimiter` rendering option, in the case when -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\n\nThe vulnerability was **rightfully disputed** due to the fact that a vulnerable configuration is extremely unlikely to exist in any real-world setup. As such, the maintainers will not provide a fix for this (non-)issue.\n\nExample of a vulnerable application -\n```js\nconst express = require('express')\nconst app = express()\nconst port = 3000\n\napp.set('view engine', 'ejs');\n\napp.get('/page', (req,res) =\u003e {\n res.render('page', req.query); // OPTS (2nd parameter) IS ATTACKER-CONTROLLED\n})\n\napp.listen(port, () =\u003e {\n console.log(\"Example app listening on port ${port}\")\n})\n```\n\nContents of `page.ejs` (very unlikely to be attacker controlled) -\n```js\n%%1\");process.mainModule.require('child_process').execSync('calc');//\n```\n\nIn this case, sending `closeDelimiter` with the same malicious code that already exists at `page.ejs` will trigger the injection -\n`http://127.0.0.1:3000/page?settings[view%20options][closeDelimiter]=1\")%3bprocess.mainModule.require('child_process').execSync('calc')%3b//`", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS does not take into account the rarity of a vulnerable configuration to exist", - "is_positive": true - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "The vulnerability can be exploited only under the following conditions -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\nThis vulnerable configuration is extremely unlikely to exist in any real-world setup.", - "is_positive": true - }, - { - "name": "The issue has been disputed by the vendor", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "Published exploit demonstrates template injection" - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2022-29078", - "cvss_v2_score": "7.5", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-94", - "CWE-74" - ], - "cwe_details": { - "CWE-74": { - "name": "Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')", - "description": "The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component." - }, - "CWE-94": { - "name": "Improper Control of Generation of Code ('Code Injection')", - "description": "The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "23" - } - ] - } - } - } - ], - "summary": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", - "severity": "Critical", - "components": { - "npm://ejs:3.1.6": { - "fixed_versions": [ - "[3.1.7]" - ], - "impact_paths": [ - [ - { - "component_id": "npm://froghome:1.0.0" - }, - { - "component_id": "npm://ejs:3.1.6" - } - ] - ] - } - }, - "issue_id": "XRAY-209002", - "extended_information": { - "short_description": "Insufficient input validation in EJS enables attackers to perform template injection when attacker can control the rendering options.", - "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to perform template injection on the `opts.outputFunctionName` variable, since the variable is injected into the template body without any escaping. Although it is unlikely that the attacker can directly control the `outputFunctionName` property, it is possible that it can be influenced in conjunction with a prototype pollution vulnerability.\n\nOnce template injection is achieved, the attacker can immediately perform remote code execution since the template engine (EJS) allows executing arbitrary JavaScript code.\n\nExample of a vulnerable Node.js application -\n```js\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst lodash = require('lodash');\nconst ejs = require('ejs');\n\nconst app = express();\n\napp\n .use(bodyParser.urlencoded({extended: true}))\n .use(bodyParser.json());\n\napp.set('views', './');\napp.set('view engine', 'ejs');\n\napp.get(\"/\", (req, res) =\u003e {\n res.render('index');\n});\n\napp.post(\"/\", (req, res) =\u003e {\n let data = {};\n let input = JSON.parse(req.body.content);\n lodash.defaultsDeep(data, input);\n res.json({message: \"OK\"});\n});\n\nlet server = app.listen(8086, '0.0.0.0', function() {\n console.log('Listening on port %d', server.address().port);\n});\n```\n\nExploiting the above example for RCE -\n`curl 127.0.0.1:8086 -v --data 'content={\"constructor\": {\"prototype\": {\"outputFunctionName\": \"a; return global.process.mainModule.constructor._load(\\\"child_process\\\").execSync(\\\"whoami\\\"); //\"}}}'\n`\n\nDue to the prototype pollution in the `lodash.defaultsDeep` call, an attacker can inject the `outputFunctionName` property with an arbitrary value. The chosen value executes an arbitrary process via the `child_process` module.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "The attacker has to find a way to get their malicious input to `opts.outputFunctionName`, which will usually require exploitation of a prototype pollution vulnerability somewhere else in the code. However, there could be cases where the attacker can pass malicious data to the render function directly because of design problems in other code using EJS.", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "There are multiple examples of exploits for this vulnerability online." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Successful exploitation of this vulnerability leads to remote code execution." - } - ], - "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\nNote that this mitigation is supposed to stop any prototype pollution attacks which can allow an attacker to control the `opts.outputFunctionName` parameter indirectly.\n\nThe mitigation will not stop any (extremely unlikely) scenarios where the JavaScript code allows external input to directly affect `opts.outputFunctionName`." - } - } - ], - "component_id": "root", - "package_type": "generic", - "status": "completed" - } - ] - }, - "jas_scans": { - "contextual_analysis": [ - { - "tool": { - "driver": { - "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", - "name": "JFrog Applicability Scanner", - "rules": [ - { - "id": "applic_CVE-2018-16487", - "name": "CVE-2018-16487", - "shortDescription": { - "text": "Scanner for CVE-2018-16487" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", - "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2019-10744", - "name": "CVE-2019-10744", - "shortDescription": { - "text": "Scanner for CVE-2019-10744" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present.", - "markdown": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2020-28500", - "name": "CVE-2020-28500", - "shortDescription": { - "text": "Scanner for CVE-2020-28500" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument.", - "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2020-8203", - "name": "CVE-2020-8203", - "shortDescription": { - "text": "Scanner for CVE-2020-8203" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present.", - "markdown": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2021-23337", - "name": "CVE-2021-23337", - "shortDescription": { - "text": "Scanner for CVE-2021-23337" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument.", - "markdown": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2022-29078", - "name": "CVE-2022-29078", - "shortDescription": { - "text": "Scanner for CVE-2022-29078" - }, - "fullDescription": { - "text": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", - "markdown": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2024-33883", - "name": "CVE-2024-33883", - "shortDescription": { - "text": "Scanner for CVE-2024-33883" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable function `ejs.compile()` is called.", - "markdown": "The scanner checks whether the vulnerable function `ejs.compile()` is called." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2023-29827", - "name": "CVE-2023-29827", - "shortDescription": { - "text": "Scanner for CVE-2023-29827" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`", - "markdown": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`" - }, - "properties": { - "applicability": "applicable", - "conclusion": "negative", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2019-1010266", - "name": "CVE-2019-1010266", - "shortDescription": { - "text": "Scanner for uncovered CVE-2019-1010266" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2018-3721", - "name": "CVE-2018-3721", - "shortDescription": { - "text": "Scanner for uncovered CVE-2018-3721" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-29041", - "name": "CVE-2024-29041", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-29041" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-39249", - "name": "CVE-2024-39249", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-39249" - }, - "fullDescription": { - "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", - "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." - }, - "properties": { - "applicability": "not_covered", - "security-severity": 6.9 - } - }, - { - "id": "applic_CVE-2024-39249", - "name": "CVE-2024-39249", - "shortDescription": { - "text": "Scanner for indirect dependency CVE-2024-39249" - }, - "fullDescription": { - "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", - "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." - }, - "properties": { - "applicability": "not_applicable" - } - } - ], - "version": "1.0" - } - }, - "invocations": [ - { - "arguments": [ - "analyzerManager/jas_scanner/jas_scanner", - "scan", - "Applicability/config.yaml" - ], - "executionSuccessful": true, - "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" - } - } - ], - "results": [ - { - "ruleId": "applic_CVE-2018-16487", - "message": { - "text": "Prototype pollution `Object.freeze` remediation was detected" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 1, - "startColumn": 0, - "endLine": 1, - "endColumn": 31, - "snippet": { - "text": "Object.freeze(Object.prototype)" - } - } - } - } - ] - }, - { - "ruleId": "applic_CVE-2018-16487", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." - } - }, - { - "ruleId": "applic_CVE-2019-10744", - "message": { - "text": "Prototype pollution `Object.freeze` remediation was detected" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 1, - "startColumn": 0, - "endLine": 1, - "endColumn": 31, - "snippet": { - "text": "Object.freeze(Object.prototype)" - } - } - } - } - ] - }, - { - "ruleId": "applic_CVE-2019-10744", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." - } - }, - { - "ruleId": "applic_CVE-2020-28500", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." - } - }, - { - "ruleId": "applic_CVE-2020-8203", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." - } - }, - { - "ruleId": "applic_CVE-2021-23337", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." - } - }, - { - "ruleId": "applic_CVE-2022-29078", - "message": { - "text": "Prototype pollution `Object.freeze` remediation was detected" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 1, - "startColumn": 0, - "endLine": 1, - "endColumn": 31, - "snippet": { - "text": "Object.freeze(Object.prototype)" - } - } - } - } - ] - }, - { - "ruleId": "applic_CVE-2022-29078", - "kind": "pass", - "message": { - "text": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." - } - }, - { - "ruleId": "applic_CVE-2024-33883", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable function `ejs.compile()` is called." - } - }, - { - "ruleId": "applic_CVE-2023-29827", - "message": { - "text": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 15, - "startColumn": 0, - "endLine": 15, - "endColumn": 29, - "snippet": { - "text": "app.set('view engine', 'ejs')" - } - } - } - } - ] - }, - { - "ruleId": "applic_CVE-2023-29827", - "message": { - "text": "The vulnerable function render is called" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 27, - "startColumn": 2, - "endLine": 27, - "endColumn": 37, - "snippet": { - "text": "res.render('pages/index',req.query)" - } - } - } - } - ] - }, - { - "ruleId": "applic_CVE-2024-39249", - "kind": "pass", - "message": { - "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." - } - } - ] - } - ], - "secrets": [ - { - "tool": { - "driver": { - "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", - "name": "JFrog Secrets scanner", - "rules": [ - { - "id": "REQ.SECRET.GENERIC.TEXT", - "name": "REQ.SECRET.GENERIC.TEXT", - "shortDescription": { - "text": "Scanner for REQ.SECRET.GENERIC.TEXT" - }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive" - } - }, - { - "id": "REQ.SECRET.GENERIC.CODE", - "name": "REQ.SECRET.GENERIC.CODE", - "shortDescription": { - "text": "Scanner for REQ.SECRET.GENERIC.CODE" - }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive" - } - }, - { - "id": "REQ.SECRET.GENERIC.URL", - "name": "REQ.SECRET.GENERIC.URL", - "shortDescription": { - "text": "Scanner for REQ.SECRET.GENERIC.URL" - }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive" - } - }, - { - "id": "REQ.SECRET.KEYS", - "name": "REQ.SECRET.KEYS", - "shortDescription": { - "text": "Scanner for REQ.SECRET.KEYS" - }, - "fullDescription": { - "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", - "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" - }, - "properties": { - "applicability": "applicable", - "conclusion": "negative", - "security-severity": 6.9 - } - } - ], - "version": "1.0" - } - }, - "invocations": [ - { - "arguments": [ - "analyzerManager/jas_scanner/jas_scanner", - "scan", - "Secrets/config.yaml" - ], - "executionSuccessful": true, - "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" - } - } - ], - "results": [ - { - "ruleId": "REQ.SECRET.KEYS", - "message": { - "text": "Secret keys were found" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" - }, - "region": { - "startLine": 1, - "startColumn": 0, - "endLine": 1, - "endColumn": 0, - "snippet": { - "text": "AKI************" - } - } - } - } - ] - }, - { - "ruleId": "REQ.SECRET.KEYS", - "message": { - "text": "Secret keys were found" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" - }, - "region": { - "startLine": 2, - "startColumn": 0, - "endLine": 2, - "endColumn": 0, - "snippet": { - "text": "Sqc************" - } - } - } - } - ] - }, - { - "ruleId": "REQ.SECRET.KEYS", - "message": { - "text": "Secret keys were found" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" - }, - "region": { - "startLine": 3, - "startColumn": 0, - "endLine": 3, - "endColumn": 0, - "snippet": { - "text": "gho************" - } - } - } - } - ] - }, - { - "ruleId": "REQ.SECRET.KEYS", - "message": { - "text": "Secret keys were found" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 10, - "startColumn": 15, - "endLine": 10, - "endColumn": 15, - "snippet": { - "text": "AKI************" - } - } - } - } - ] - }, - { - "ruleId": "REQ.SECRET.KEYS", - "message": { - "text": "Secret keys were found" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 11, - "startColumn": 12, - "endLine": 11, - "endColumn": 12, - "snippet": { - "text": "\"Sq************" - } - } - } - } - ] - } - ] - } - ], - "iac": [ - { - "tool": { - "driver": { - "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/infrastructure-as-code-iac", - "name": "JFrog Terraform scanner", - "rules": [], - "version": "1.8.3" - } - }, - "invocations": [ - { - "arguments": [ - "analyzerManager/iac_scanner/tf_scanner", - "scan", - "IaC/config.yaml" - ], - "executionSuccessful": true, - "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" - } - } - ], - "results": [] - } - ], - "sast": [ - { - "tool": { - "driver": { - "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sast", - "name": "USAF", - "rules": [ - { - "id": "js-express-without-helmet", - "shortDescription": { - "text": "Express Not Using Helmet" - }, - "fullDescription": { - "text": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n", - "markdown": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n" - }, - "properties": { - "security-severity": 3.9 - } - }, - { - "id": "js-insecure-random", - "shortDescription": { - "text": "Use of Insecure Random" - }, - "fullDescription": { - "text": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n", - "markdown": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" - }, - "defaultConfiguration": { - "parameters": { - "properties": { - "CWE": "338" - } - } - }, - "properties": { - "security-severity": 3.9 - } - }, - { - "id": "js-template-injection", - "shortDescription": { - "text": "Template Object Injection" - }, - "fullDescription": { - "text": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n", - "markdown": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n" - }, - "defaultConfiguration": { - "parameters": { - "properties": { - "CWE": "73" - } - } - }, - "properties": { - "security-severity": 8.9 - } - } - ], - "version": "1.8.3" - } - }, - "invocations": [ - { - "arguments": [ - "analyzerManager/zd_scanner/scanner", - "scan", - "Sast/results.sarif", - "Sast/config.yaml" - ], - "executionSuccessful": true, - "workingDirectory": { - "uri": "/Users/user/ejs-frog-demo" - } - } - ], - "results": [ - { - "ruleId": "js-insecure-random", - "level": "note", - "message": { - "text": "Use of Insecure Random" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" - }, - "region": { - "startLine": 136, - "startColumn": 22, - "endLine": 136, - "endColumn": 35, - "snippet": { - "text": "Math.random()" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "public.js.bootstrap.^_0.Util.getUID" - } - ] - } - ] - }, - { - "ruleId": "js-insecure-random", - "level": "note", - "message": { - "text": "Use of Insecure Random" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" - }, - "region": { - "startLine": 135, - "startColumn": 22, - "endLine": 135, - "endColumn": 35, - "snippet": { - "text": "Math.random()" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "public.js.bootstrap\u003cdot\u003ebundle.^_0.Util.getUID" - } - ] - } - ] - }, - { - "ruleId": "js-express-without-helmet", - "level": "note", - "message": { - "text": "Express Not Using Helmet" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 8, - "startColumn": 11, - "endLine": 8, - "endColumn": 20, - "snippet": { - "text": "express()" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "server" - } - ] - } - ] - }, - { - "ruleId": "js-template-injection", - "level": "error", - "message": { - "text": "Template Object Injection" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 26, - "startColumn": 28, - "endLine": 26, - "endColumn": 37, - "snippet": { - "text": "req.query" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "server.^_4" - } - ] - } - ], - "codeFlows": [ - { - "threadFlows": [ - { - "locations": [ - { - "location": { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 22, - "startColumn": 23, - "endLine": 22, - "endColumn": 26, - "snippet": { - "text": "req" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "server.^_4" - } - ] - } - }, - { - "location": { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 27, - "startColumn": 28, - "endLine": 27, - "endColumn": 31, - "snippet": { - "text": "req" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "server.^_4" - } - ] - } - }, - { - "location": { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 27, - "startColumn": 28, - "endLine": 27, - "endColumn": 37, - "snippet": { - "text": "req.query" - } - } - }, - "logicalLocations": [ - { - "fullyQualifiedName": "server.^_4" - } - ] - } - } - ] - } - ] - } - ] - } - ] - } - ] - } - } - ] - } \ No newline at end of file diff --git a/tests/testdata/other/output/formats/audit_simple_json.json b/tests/testdata/other/output/formats/audit_simple_json.json deleted file mode 100644 index 44a43ac1..00000000 --- a/tests/testdata/other/output/formats/audit_simple_json.json +++ /dev/null @@ -1,917 +0,0 @@ -{ - "vulnerabilities": [ - { - "severity": "Critical", - "impactedPackageName": "ejs", - "impactedPackageVersion": "3.1.6", - "impactedPackageType": "npm", - "components": [ - { - "name": "ejs", - "version": "3.1.6", - "location": { - "file": "/Users/user/ejs-frog-demo/package.json" - } - } - ], - "summary": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", - "applicable": "Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2023-29827", - "cvssV2": "", - "cvssV3": "9.8", - "applicability": { - "status": "Applicable", - "scannerDescription": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`", - "evidence": [ - { - "file": "server.js", - "startLine": 15, - "endLine": 15, - "endColumn": 29, - "snippet": "app.set('view engine', 'ejs')", - "reason": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" - } - ] - } - } - ], - "issueId": "XRAY-520200", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "ejs", - "version": "3.1.6" - } - ] - ], - "jfrogResearchInformation": { - "severity": "Low", - "summary": "Insufficient input validation can lead to template injection in ejs when attackers can control both the rendered template and rendering options.", - "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to bypass ejs' template injection restrictions, by abusing the `closeDelimiter` rendering option, in the case when -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\n\nThe vulnerability was **rightfully disputed** due to the fact that a vulnerable configuration is extremely unlikely to exist in any real-world setup. As such, the maintainers will not provide a fix for this (non-)issue.\n\nExample of a vulnerable application -\n```js\nconst express = require('express')\nconst app = express()\nconst port = 3000\n\napp.set('view engine', 'ejs');\n\napp.get('/page', (req,res) =\u003e {\n res.render('page', req.query); // OPTS (2nd parameter) IS ATTACKER-CONTROLLED\n})\n\napp.listen(port, () =\u003e {\n console.log(\"Example app listening on port ${port}\")\n})\n```\n\nContents of `page.ejs` (very unlikely to be attacker controlled) -\n```js\n%%1\");process.mainModule.require('child_process').execSync('calc');//\n```\n\nIn this case, sending `closeDelimiter` with the same malicious code that already exists at `page.ejs` will trigger the injection -\n`http://127.0.0.1:3000/page?settings[view%20options][closeDelimiter]=1\")%3bprocess.mainModule.require('child_process').execSync('calc')%3b//`", - "severityReasons": [ - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS does not take into account the rarity of a vulnerable configuration to exist", - "isPositive": true - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "The vulnerability can be exploited only under the following conditions -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\nThis vulnerable configuration is extremely unlikely to exist in any real-world setup.", - "isPositive": true - }, - { - "name": "The issue has been disputed by the vendor", - "isPositive": true - }, - { - "name": "The issue has an exploit published", - "description": "Published exploit demonstrates template injection" - } - ] - } - }, - { - "severity": "Medium", - "impactedPackageName": "lodash", - "impactedPackageVersion": "4.17.0", - "impactedPackageType": "npm", - "components": [ - { - "name": "lodash", - "version": "4.17.0", - "location": { - "file": "/Users/user/ejs-frog-demo/package.json" - } - } - ], - "summary": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", - "applicable": "Not Covered", - "fixedVersions": [ - "[4.17.11]" - ], - "cves": [ - { - "id": "CVE-2019-1010266", - "cvssV2": "4.0", - "cvssV3": "6.5", - "applicability": { - "status": "Not Covered" - } - } - ], - "issueId": "XRAY-85049", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "lodash", - "version": "4.17.0" - } - ] - ], - "jfrogResearchInformation": null - }, - { - "severity": "Medium", - "impactedPackageName": "lodash", - "impactedPackageVersion": "4.17.0", - "impactedPackageType": "npm", - "components": [ - { - "name": "lodash", - "version": "4.17.0", - "location": { - "file": "/Users/user/ejs-frog-demo/package.json" - } - } - ], - "summary": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", - "applicable": "Not Covered", - "fixedVersions": [ - "[4.17.5]" - ], - "cves": [ - { - "id": "CVE-2018-3721", - "cvssV2": "4.0", - "cvssV3": "6.5", - "applicability": { - "status": "Not Covered" - } - } - ], - "issueId": "XRAY-72918", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "lodash", - "version": "4.17.0" - } - ] - ], - "jfrogResearchInformation": null - }, - { - "severity": "Medium", - "impactedPackageName": "express", - "impactedPackageVersion": "4.18.2", - "impactedPackageType": "npm", - "components": [ - { - "name": "express", - "version": "4.18.2", - "location": { - "file": "/Users/user/ejs-frog-demo/package.json" - } - } - ], - "summary": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", - "applicable": "Not Covered", - "fixedVersions": [ - "[4.19.2]", - "[5.0.0-beta.3]" - ], - "cves": [ - { - "id": "CVE-2024-29041", - "cvssV2": "", - "cvssV3": "6.1", - "applicability": { - "status": "Not Covered" - } - } - ], - "issueId": "XRAY-594935", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "express", - "version": "4.18.2" - } - ] - ], - "jfrogResearchInformation": null - }, - { - "severity": "Unknown", - "impactedPackageName": "async", - "impactedPackageVersion": "3.2.4", - "impactedPackageType": "npm", - "components": [ - { - "name": "ejs", - "version": "3.1.6", - "location": { - "file": "/Users/user/ejs-frog-demo/package.json" - } - } - ], - "summary": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", - "applicable": "Not Covered", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2024-39249", - "cvssV2": "", - "cvssV3": "", - "applicability": { - "status": "Not Covered", - "scannerDescription": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." - } - } - ], - "issueId": "XRAY-609848", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "ejs", - "version": "3.1.6" - }, - { - "name": "jake", - "version": "10.8.7" - }, - { - "name": "async", - "version": "3.2.4" - } - ] - ], - "jfrogResearchInformation": { - "severity": "Low", - "summary": "ReDoS in Async may lead to denial of service while parsing malformed source code.", - "severityReasons": [ - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The reported CVSS does not reflect the severity of the vulnerability.", - "isPositive": true - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "To exploit this issue an attacker must change the source code of the application. In cases where an attacker can already modify (or fully control) the source code, the attacker can immediately achieve arbitrary code execution - thus this issue has almost no security impact.", - "isPositive": true - }, - { - "name": "The issue has an exploit published", - "description": "A proof-of-concept has been published in the advisory." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The issue requires the use of the `async.autoInject` function to be vulnerable.", - "isPositive": true - } - ] - } - }, - { - "severity": "Critical", - "impactedPackageName": "lodash", - "impactedPackageVersion": "4.17.0", - "impactedPackageType": "npm", - "components": [ - { - "name": "lodash", - "version": "4.17.0", - "location": { - "file": "/Users/user/ejs-frog-demo/package.json" - } - } - ], - "summary": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", - "applicable": "Not Applicable", - "fixedVersions": [ - "[4.17.12]" - ], - "cves": [ - { - "id": "CVE-2019-10744", - "cvssV2": "6.4", - "cvssV3": "9.1", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present.", - "evidence": [ - { - "file": "server.js", - "startLine": 1, - "endLine": 1, - "endColumn": 31, - "snippet": "Object.freeze(Object.prototype)", - "reason": "Prototype pollution `Object.freeze` remediation was detected" - } - ] - } - } - ], - "issueId": "XRAY-85679", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "lodash", - "version": "4.17.0" - } - ] - ], - "jfrogResearchInformation": { - "severity": "High", - "summary": "Insufficient input validation in lodash defaultsDeep() leads to prototype pollution.", - "details": "[lodash](https://www.npmjs.com/package/lodash) is a modern JavaScript utility library delivering modularity, performance, \u0026 extras.\n\nThe function `defaultsDeep` was found to be vulnerable to prototype pollution, when accepting arbitrary source objects from untrusted input\n\nExample of code vulnerable to this issue - \n```js\nconst lodash = require('lodash'); \nconst evilsrc = {constructor: {prototype: {evilkey: \"evilvalue\"}}};\nlodash.defaultsDeep({}, evilsrc)\n```", - "severityReasons": [ - { - "name": "The issue has an exploit published", - "description": "A public PoC demonstrates exploitation of this issue" - }, - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", - "isPositive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "An attacker must find remote input that propagates into the `defaultsDeep` method (2nd arg)", - "isPositive": true - } - ], - "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." - } - }, - { - "severity": "Critical", - "impactedPackageName": "ejs", - "impactedPackageVersion": "3.1.6", - "impactedPackageType": "npm", - "components": [ - { - "name": "ejs", - "version": "3.1.6", - "location": { - "file": "/Users/user/ejs-frog-demo/package.json" - } - } - ], - "summary": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", - "applicable": "Not Applicable", - "fixedVersions": [ - "[3.1.7]" - ], - "cves": [ - { - "id": "CVE-2022-29078", - "cvssV2": "7.5", - "cvssV3": "9.8", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", - "evidence": [ - { - "file": "server.js", - "startLine": 1, - "endLine": 1, - "endColumn": 31, - "snippet": "Object.freeze(Object.prototype)", - "reason": "Prototype pollution `Object.freeze` remediation was detected" - } - ] - } - } - ], - "issueId": "XRAY-209002", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "ejs", - "version": "3.1.6" - } - ] - ], - "jfrogResearchInformation": { - "severity": "Medium", - "summary": "Insufficient input validation in EJS enables attackers to perform template injection when attacker can control the rendering options.", - "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to perform template injection on the `opts.outputFunctionName` variable, since the variable is injected into the template body without any escaping. Although it is unlikely that the attacker can directly control the `outputFunctionName` property, it is possible that it can be influenced in conjunction with a prototype pollution vulnerability.\n\nOnce template injection is achieved, the attacker can immediately perform remote code execution since the template engine (EJS) allows executing arbitrary JavaScript code.\n\nExample of a vulnerable Node.js application -\n```js\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst lodash = require('lodash');\nconst ejs = require('ejs');\n\nconst app = express();\n\napp\n .use(bodyParser.urlencoded({extended: true}))\n .use(bodyParser.json());\n\napp.set('views', './');\napp.set('view engine', 'ejs');\n\napp.get(\"/\", (req, res) =\u003e {\n res.render('index');\n});\n\napp.post(\"/\", (req, res) =\u003e {\n let data = {};\n let input = JSON.parse(req.body.content);\n lodash.defaultsDeep(data, input);\n res.json({message: \"OK\"});\n});\n\nlet server = app.listen(8086, '0.0.0.0', function() {\n console.log('Listening on port %d', server.address().port);\n});\n```\n\nExploiting the above example for RCE -\n`curl 127.0.0.1:8086 -v --data 'content={\"constructor\": {\"prototype\": {\"outputFunctionName\": \"a; return global.process.mainModule.constructor._load(\\\"child_process\\\").execSync(\\\"whoami\\\"); //\"}}}'\n`\n\nDue to the prototype pollution in the `lodash.defaultsDeep` call, an attacker can inject the `outputFunctionName` property with an arbitrary value. The chosen value executes an arbitrary process via the `child_process` module.", - "severityReasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "The attacker has to find a way to get their malicious input to `opts.outputFunctionName`, which will usually require exploitation of a prototype pollution vulnerability somewhere else in the code. However, there could be cases where the attacker can pass malicious data to the render function directly because of design problems in other code using EJS.", - "isPositive": true - }, - { - "name": "The issue has an exploit published", - "description": "There are multiple examples of exploits for this vulnerability online." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Successful exploitation of this vulnerability leads to remote code execution." - } - ], - "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\nNote that this mitigation is supposed to stop any prototype pollution attacks which can allow an attacker to control the `opts.outputFunctionName` parameter indirectly.\n\nThe mitigation will not stop any (extremely unlikely) scenarios where the JavaScript code allows external input to directly affect `opts.outputFunctionName`." - } - }, - { - "severity": "High", - "impactedPackageName": "lodash", - "impactedPackageVersion": "4.17.0", - "impactedPackageType": "npm", - "components": [ - { - "name": "lodash", - "version": "4.17.0", - "location": { - "file": "/Users/user/ejs-frog-demo/package.json" - } - } - ], - "summary": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", - "applicable": "Not Applicable", - "fixedVersions": [ - "[4.17.21]" - ], - "cves": [ - { - "id": "CVE-2021-23337", - "cvssV2": "6.5", - "cvssV3": "7.2", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." - } - } - ], - "issueId": "XRAY-140575", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "lodash", - "version": "4.17.0" - } - ] - ], - "jfrogResearchInformation": { - "severity": "Medium", - "summary": "Improper sanitization in the lodash template function leads to JavaScript code injection through the options argument.", - "details": "JavaScript-based applications (both frontend and backend) that use the [template function](https://lodash.com/docs/4.17.15#template) -`_.template([string=''], [options={}])` from the [lodash](https://lodash.com/) utility library and provide the `options` argument (specifically the `variable` option) from untrusted user input, are vulnerable to JavaScript code injection. This issue can be easily exploited, and an exploitation example is [publicly available](https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c#diff-a561630bb56b82342bc66697aee2ad96efddcbc9d150665abd6fb7ecb7c0ab2fR22303) in the fix tests that was introduced in version 4.17.21 - \n```js\nlodash.template('', { variable: '){console.log(process.env)}; with(obj' })()\n```", - "severityReasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "It is highly unlikely that a JS program will accept arbitrary remote input into the template's `options` argument", - "isPositive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker must find remote input that propagates into the `options` argument of a `template` call", - "isPositive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Leads to remote code execution through JS code injection" - }, - { - "name": "The issue has an exploit published", - "description": "Published exploit demonstrates arbitrary JS code execution" - } - ] - } - }, - { - "severity": "High", - "impactedPackageName": "lodash", - "impactedPackageVersion": "4.17.0", - "impactedPackageType": "npm", - "components": [ - { - "name": "lodash", - "version": "4.17.0", - "location": { - "file": "/Users/user/ejs-frog-demo/package.json" - } - } - ], - "summary": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", - "applicable": "Not Applicable", - "fixedVersions": [ - "[4.17.19]" - ], - "cves": [ - { - "id": "CVE-2020-8203", - "cvssV2": "5.8", - "cvssV3": "7.4", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." - } - } - ], - "issueId": "XRAY-114089", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "lodash", - "version": "4.17.0" - } - ] - ], - "jfrogResearchInformation": { - "severity": "Critical", - "summary": "Prototype pollution in lodash object merging and zipping functions leads to code injection.", - "details": "[lodash](https://lodash.com/) is a JavaScript library which provides utility functions for common programming tasks.\n\nJavaScript frontend and Node.js-based backend applications that merge or zip objects using the lodash functions `mergeWith`, `merge` and `zipObjectDeep` are vulnerable to [prototype pollution](https://medium.com/node-modules/what-is-prototype-pollution-and-why-is-it-such-a-big-deal-2dd8d89a93c) if one or more of the objects it receives as arguments are obtained from user input. \nAn attacker controlling this input given to the vulnerable functions can inject properties to JavaScript special objects such as [Object.prototype](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes) from which all JavaScript objects inherit properties and methods. Any change on `Object.prototype` properties will then propagate through the prototype chain inheritance to all of the objects in a JavaScript application. This in turn would allow an attacker to add new properties or modify existing properties which will have application specific implications that could lead to DoS (denial of service), authentication bypass, privilege escalation and even RCE (remote code execution) in [some cases](https://youtu.be/LUsiFV3dsK8?t=1152). \nAs an example for privilege escalation, consider a JavaScript application that has a `user` object which has a Boolean property of `user.isAdmin` which is used to decide which actions the user may take. If an attacker can modify or add the `isAdmin` property through prototype pollution, it can escalate the privileges of its own user to those of an admin. \nAs exploitation is usually application specific, successful exploitation is much more likely if an attacker have access to the JavaScript application code. As such, frontend applications are more vulnerable to this vulnerability than Node.js backend applications.", - "severityReasons": [ - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "isPositive": true - }, - { - "name": "The issue can be exploited by attackers over the network" - }, - { - "name": "The issue is trivial to exploit and does not require a published writeup or PoC" - } - ], - "remediation": "##### Deployment mitigations\n\nAs general guidelines against prototype pollution, first consider not merging objects originating from user input or using a Map structure instead of an object. If merging objects is needed, look into creating objects without a prototype with `Object.create(null)` or into freezing `Object.prototype` with `Object.freeze()`. Finally, it is always best to perform input validation with a a [JSON schema validator](https://github.com/ajv-validator/ajv), which could mitigate this issue entirely in many cases." - } - }, - { - "severity": "Medium", - "impactedPackageName": "lodash", - "impactedPackageVersion": "4.17.0", - "impactedPackageType": "npm", - "components": [ - { - "name": "lodash", - "version": "4.17.0", - "location": { - "file": "/Users/user/ejs-frog-demo/package.json" - } - } - ], - "summary": "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.", - "applicable": "Not Applicable", - "fixedVersions": [ - "[4.17.11]" - ], - "cves": [ - { - "id": "CVE-2018-16487", - "cvssV2": "6.8", - "cvssV3": "5.6", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", - "evidence": [ - { - "file": "server.js", - "startLine": 1, - "endLine": 1, - "endColumn": 31, - "snippet": "Object.freeze(Object.prototype)", - "reason": "Prototype pollution `Object.freeze` remediation was detected" - } - ] - } - } - ], - "issueId": "XRAY-75300", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "lodash", - "version": "4.17.0" - } - ] - ], - "jfrogResearchInformation": { - "severity": "High", - "summary": "Insufficient input validation in the Lodash library leads to prototype pollution.", - "details": "The [Lodash](https://lodash.com/) library is an open-source JavaScript project that simplifies operations on string, arrays, numbers, and other objects. It is widely used in connected devices. \n\nThe `merge`, `mergeWith`, and `defaultsDeep` methods in Lodash are vulnerable to [prototype pollution](https://shieldfy.io/security-wiki/prototype-pollution/introduction-to-prototype-pollution/). Attackers can exploit this vulnerability by specifying a crafted `sources` parameter to any of these methods, which can modify the prototype properties of the `Object`, `Function`, `Array`, `String`, `Number`, and `Boolean` objects. A public [exploit](https://hackerone.com/reports/380873) exists which performs the prototype pollution with an arbitrary key and value.\n\nThe library implementation has a bug in the `safeGet()` function in the `lodash.js` module that allows for adding or modifying `prototype` properties of various objects. The official [solution](https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad) fixes the bug by explicitly forbidding the addition or modification of `prototype` properties.\n\nA related CVE (CVE-2018-3721) covers the same issue prior to Lodash version 4.17.5, but the fix for that was incomplete.", - "severityReasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "An attacker must find remote input that propagates into one of the following methods - \n* `merge` - 2nd argument\n* `mergeWith` - 2nd argument\n* `defaultsDeep` - 2nd argument", - "isPositive": true - }, - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", - "isPositive": true - }, - { - "name": "The issue has an exploit published", - "description": "A public PoC demonstrated exploitation by injecting an attacker controlled key and value into the prototype" - } - ], - "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." - } - }, - { - "severity": "Medium", - "impactedPackageName": "ejs", - "impactedPackageVersion": "3.1.6", - "impactedPackageType": "npm", - "components": [ - { - "name": "ejs", - "version": "3.1.6", - "location": { - "file": "/Users/user/ejs-frog-demo/package.json" - } - } - ], - "summary": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", - "applicable": "Not Applicable", - "fixedVersions": [ - "[3.1.10]" - ], - "cves": [ - { - "id": "CVE-2024-33883", - "cvssV2": "", - "cvssV3": "", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether the vulnerable function `ejs.compile()` is called." - } - } - ], - "issueId": "XRAY-599735", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "ejs", - "version": "3.1.6" - } - ] - ], - "jfrogResearchInformation": { - "severity": "Medium", - "summary": "Insufficient input validation in EJS may lead to prototype pollution.", - "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as `EJS`, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nA prototype pollution gadget within the EJS template engine could potentially be leveraged by attackers to achieve remote code execution or DoS via prototype pollution.\n\n```\nfunction Template(text, opts) {\n opts = opts || utils.createNullProtoObjWherePossible();\n```\n\nWhen checking for the presence of a property within an object variable, the lookup scope isn't explicitly defined. In JavaScript, the absence of a defined lookup scope prompts a search up to the root prototype (`Object.prototype`). This could potentially be under the control of an attacker if another prototype pollution vulnerability is present within the application.\n\nIf the application server is using the EJS as the backend template engine, and there is another prototype pollution vulnerability in the application, then the attacker could leverage the found gadgets in the EJS template engine to escalate the prototype pollution to remote code execution or DoS.\n\nThe following code will execute a command on the server by polluting `opts.escapeFunction`:\n \n```\nconst express = require('express');\nconst app = express();\nconst port = 8008;\nconst ejs = require('ejs');\n\n// Set EJS as the view engine\napp.set('view engine', 'ejs');\n\napp.get('/', (req, res) =\u003e {\n \n const data = {title: 'Welcome', message: 'Hello'};\n\n // Sample EJS template string\n const templateString = `\u003chtml\u003e\u003chead\u003e\u003ctitle\u003e\u003c%= title %\u003e\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003ch1\u003e\u003c%= message %\u003e\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e`;\n\n const { exec } = require('child_process');\n\n function myFunc() {\n exec('bash -c \"echo 123\"', (error, stdout, stderr) =\u003e {\n if (error) {\n console.error(`exec error: ${error}`);\n return;\n }\n if (stderr){\n console.log(`stderr : ${stderr}`);\n return;\n }\n // Handle success\n console.log(`Command executed successfully. Output: ${stdout}`);\n });\n }\n\n const options = {client:false};\n\n Object.prototype.escapeFunction = myFunc;\n \n const compiledTemplate = ejs.compile(templateString, options);\n const renderedHtml = compiledTemplate(data);\n res.send(renderedHtml);\n});\n\n// Start the server\napp.listen(port, () =\u003e {\n console.log(`Server is running on http://localhost:${port}`);\n});\n```", - "severityReasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "Attackers can only leverage this vulnerability when the application server is using the EJS as the backend template engine. Moreover, there must be a second prototype pollution vulnerability in the application.", - "isPositive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "CVSS does not take into account the unlikely prerequisites necessary for exploitation.", - "isPositive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "A prototype pollution attack allows the attacker to inject new properties into all JavaScript objects.\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable." - } - ] - } - }, - { - "severity": "Medium", - "impactedPackageName": "lodash", - "impactedPackageVersion": "4.17.0", - "impactedPackageType": "npm", - "components": [ - { - "name": "lodash", - "version": "4.17.0", - "location": { - "file": "/Users/user/ejs-frog-demo/package.json" - } - } - ], - "summary": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", - "applicable": "Not Applicable", - "fixedVersions": [ - "[4.17.21]" - ], - "cves": [ - { - "id": "CVE-2020-28500", - "cvssV2": "5.0", - "cvssV3": "5.3", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." - } - } - ], - "issueId": "XRAY-140562", - "references": null, - "impactPaths": [ - [ - { - "name": "froghome", - "version": "1.0.0" - }, - { - "name": "lodash", - "version": "4.17.0" - } - ] - ], - "jfrogResearchInformation": { - "severity": "Medium", - "summary": "ReDoS in lodash could lead to a denial of service when handling untrusted strings.", - "details": "JavaScript-based applications that use [lodash](https://github.com/lodash/lodash) and specifically the [_.toNumber](https://lodash.com/docs/4.17.15#toNumber), [_.trim](https://lodash.com/docs/4.17.15#trim) and [_.trimEnd](https://lodash.com/docs/4.17.15#trimEnd) functions, could be vulnerable to DoS (Denial of Service) through a faulty regular expression that introduces a ReDoS (Regular Expression DoS) vulnerability. This vulnerability is only triggered if untrusted user input flows into these vulnerable functions and the attacker can supply arbitrary long strings (over 50kB) that contain whitespaces. \n\nOn a modern Core i7-based system, calling the vulnerable functions with a 50kB string could take between 2 to 3 seconds to execute and 4.5 minutes for a longer 500kB string. The fix improved the regular expression performance so it took only a few milliseconds on the same Core i7-based system. This vulnerability is easily exploitable as all is required is to build a string that triggers it as can be seen in this PoC reproducing code - \n\n```js\nvar untrusted_user_input_50k = \"a\" + ' '.repeat(50000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_50k); // should take a few seconds to run\nvar untrusted_user_input_500k = \"a\" + ' '.repeat(500000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_500k); // should take a few minutes to run\n```", - "severityReasons": [ - { - "name": "The issue has an exploit published", - "description": "Public exploit demonstrated ReDoS" - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "Exploitation depends on parsing user input by the `.toNumber`, `.trim` or `.trimEnd` `lodash` functions, and requires the input to contain whitespaces and be very long (over 50KB)", - "isPositive": true - } - ], - "remediation": "##### Deployment mitigations\n\nTrim untrusted strings based on size before providing it to the vulnerable functions by using the `substring` function to with a fixed maximum size like so - ```js untrusted_user_input.substring(0, max_string_size_less_than_50kB); ```" - } - } - ], - "securityViolations": null, - "licensesViolations": null, - "licenses": null, - "operationalRiskViolations": null, - "secrets": [ - { - "severity": "Medium", - "file": "server.js", - "startLine": 11, - "startColumn": 15, - "endLine": 11, - "endColumn": 15, - "snippet": "AKI************", - "finding": "Secret keys were found", - "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" - }, - { - "severity": "Medium", - "file": "server.js", - "startLine": 12, - "startColumn": 12, - "endLine": 12, - "endColumn": 12, - "snippet": "\"Sq************", - "finding": "Secret keys were found", - "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" - }, - { - "severity": "Medium", - "file": "fake-creds.txt", - "startLine": 1, - "endLine": 1, - "snippet": "AKI************", - "finding": "Secret keys were found", - "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" - }, - { - "severity": "Medium", - "file": "fake-creds.txt", - "startLine": 2, - "endLine": 2, - "snippet": "Sqc************", - "finding": "Secret keys were found", - "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" - }, - { - "severity": "Medium", - "file": "fake-creds.txt", - "startLine": 3, - "endLine": 3, - "snippet": "gho************", - "finding": "Secret keys were found", - "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" - } - ], - "iacViolations": null, - "sastViolations": [ - { - "severity": "High", - "file": "server.js", - "startLine": 27, - "startColumn": 28, - "endLine": 27, - "endColumn": 37, - "snippet": "req.query", - "finding": "Template Object Injection", - "scannerDescription": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n", - "codeFlow": [ - [ - { - "file": "server.js", - "startLine": 22, - "startColumn": 23, - "endLine": 22, - "endColumn": 26, - "snippet": "req" - }, - { - "file": "server.js", - "startLine": 27, - "startColumn": 28, - "endLine": 27, - "endColumn": 31, - "snippet": "req" - }, - { - "file": "server.js", - "startLine": 27, - "startColumn": 28, - "endLine": 27, - "endColumn": 37, - "snippet": "req.query" - } - ] - ] - }, - { - "severity": "Low", - "file": "server.js", - "startLine": 9, - "startColumn": 11, - "endLine": 9, - "endColumn": 20, - "snippet": "express()", - "finding": "Express Not Using Helmet", - "scannerDescription": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n" - }, - { - "severity": "Low", - "file": "public/js/bootstrap.js", - "startLine": 136, - "startColumn": 22, - "endLine": 136, - "endColumn": 35, - "snippet": "Math.random()", - "finding": "Use of Insecure Random", - "scannerDescription": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" - }, - { - "severity": "Low", - "file": "public/js/bootstrap.bundle.js", - "startLine": 135, - "startColumn": 22, - "endLine": 135, - "endColumn": 35, - "snippet": "Math.random()", - "finding": "Use of Insecure Random", - "scannerDescription": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" - } - ], - "errors": null, - "multiScanId": "7d5e4733-3f93-11ef-8147-e610d09d7daa" -} \ No newline at end of file diff --git a/tests/testdata/other/output/formats/audit_summary.json b/tests/testdata/other/output/formats/audit_summary.json deleted file mode 100644 index d0da55a1..00000000 --- a/tests/testdata/other/output/formats/audit_summary.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "scans": [ - { - "target": "/Users/user/ejs-frog-demo", - "vulnerabilities": { - "sca": { - "sca": { - "Critical": { - "Applicable": 3 - }, - "High": { - "Not Applicable": 2 - }, - "Medium": { - "Applicable": 1, - "Not Applicable": 2, - "Not Covered": 3 - }, - "Unknown": { - "Not Covered": 1 - } - }, - "unique_findings": 12 - }, - "iac": {}, - "secrets": { - "Medium": 5 - }, - "sast": { - "High": 1, - "Low": 3 - } - } - } - ] -} \ No newline at end of file diff --git a/tests/testdata/output/audit/audit_results.json b/tests/testdata/output/audit/audit_results.json new file mode 100644 index 00000000..e64adb15 --- /dev/null +++ b/tests/testdata/output/audit/audit_results.json @@ -0,0 +1,2505 @@ +{ + "xray_version": "3.104.8", + "jas_entitled": true, + "command_type": "source_code", + "multi_scan_id": "7d5e4733-3f93-11ef-8147-e610d09d7daa", + "targets": [ + { + "target": "/Users/user/ejs-frog-demo", + "technology": "npm", + "sca_scans": { + "is_multiple_root_project": false, + "descriptors": [ + "/Users/user/ejs-frog-demo/package.json" + ], + "xray_scan": [ + { + "scan_id": "711851ce-68c4-4dfd-7afb-c29737ebcb96", + "violations": [ + { + "summary": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", + "severity": "High", + "type": "security", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.19]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-114089", + "cves": [ + { + "cve": "CVE-2020-8203", + "cvss_v2_score": "5.8", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:P/A:P", + "cvss_v3_score": "7.4", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:H" + } + ], + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2020-8203", + "https://www.oracle.com/security-alerts/cpuapr2022.html", + "https://hackerone.com/reports/864701", + "https://hackerone.com/reports/712065", + "https://github.com/advisories/GHSA-p6mc-m468-83gw", + "https://www.oracle.com//security-alerts/cpujul2021.html", + "https://github.com/lodash/lodash/issues/4744", + "https://www.oracle.com/security-alerts/cpuApr2021.html", + "https://github.com/github/advisory-database/pull/2884", + "https://www.oracle.com/security-alerts/cpujan2022.html", + "https://github.com/lodash/lodash/commit/c84fe82760fb2d3e03a63379b297a1cc1a2fce12", + "https://security.netapp.com/advisory/ntap-20200724-0006/", + "https://web.archive.org/web/20210914001339/https://github.com/lodash/lodash/issues/4744", + "https://www.oracle.com/security-alerts/cpuoct2021.html", + "https://github.com/lodash/lodash/issues/4874", + "https://github.com/lodash/lodash/wiki/Changelog#v41719" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-114089\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "Prototype pollution in lodash object merging and zipping functions leads to code injection.", + "full_description": "[lodash](https://lodash.com/) is a JavaScript library which provides utility functions for common programming tasks.\n\nJavaScript frontend and Node.js-based backend applications that merge or zip objects using the lodash functions `mergeWith`, `merge` and `zipObjectDeep` are vulnerable to [prototype pollution](https://medium.com/node-modules/what-is-prototype-pollution-and-why-is-it-such-a-big-deal-2dd8d89a93c) if one or more of the objects it receives as arguments are obtained from user input. \nAn attacker controlling this input given to the vulnerable functions can inject properties to JavaScript special objects such as [Object.prototype](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes) from which all JavaScript objects inherit properties and methods. Any change on `Object.prototype` properties will then propagate through the prototype chain inheritance to all of the objects in a JavaScript application. This in turn would allow an attacker to add new properties or modify existing properties which will have application specific implications that could lead to DoS (denial of service), authentication bypass, privilege escalation and even RCE (remote code execution) in [some cases](https://youtu.be/LUsiFV3dsK8?t=1152). \nAs an example for privilege escalation, consider a JavaScript application that has a `user` object which has a Boolean property of `user.isAdmin` which is used to decide which actions the user may take. If an attacker can modify or add the `isAdmin` property through prototype pollution, it can escalate the privileges of its own user to those of an admin. \nAs exploitation is usually application specific, successful exploitation is much more likely if an attacker have access to the JavaScript application code. As such, frontend applications are more vulnerable to this vulnerability than Node.js backend applications.", + "jfrog_research_severity": "Critical", + "jfrog_research_severity_reasons": [ + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "is_positive": true + }, + { + "name": "The issue can be exploited by attackers over the network" + }, + { + "name": "The issue is trivial to exploit and does not require a published writeup or PoC" + } + ], + "remediation": "##### Deployment mitigations\n\nAs general guidelines against prototype pollution, first consider not merging objects originating from user input or using a Map structure instead of an object. If merging objects is needed, look into creating objects without a prototype with `Object.create(null)` or into freezing `Object.prototype` with `Object.freeze()`. Finally, it is always best to perform input validation with a a [JSON schema validator](https://github.com/ajv-validator/ajv), which could mitigate this issue entirely in many cases." + } + }, + { + "summary": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", + "severity": "Medium", + "type": "security", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.5]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-72918", + "cves": [ + { + "cve": "CVE-2018-3721", + "cvss_v2_score": "4.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:S/C:N/I:P/A:N", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N" + } + ], + "references": [ + "https://www.npmjs.com/advisories/577", + "https://hackerone.com/reports/310443", + "https://github.com/advisories/GHSA-fvqr-27wr-82fm", + "https://nvd.nist.gov/vuln/detail/CVE-2018-3721", + "https://security.netapp.com/advisory/ntap-20190919-0004", + "https://security.netapp.com/advisory/ntap-20190919-0004/", + "https://github.com/lodash/lodash/commit/d8e069cc3410082e44eb18fcf8e7f3d08ebe1d4a" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-72918\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", + "severity": "Medium", + "type": "security", + "components": { + "npm://express:4.18.2": { + "fixed_versions": [ + "[4.19.2]", + "[5.0.0-beta.3]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://express:4.18.2" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-594935", + "cves": [ + { + "cve": "CVE-2024-29041", + "cvss_v3_score": "6.1", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N" + } + ], + "references": [ + "https://github.com/koajs/koa/issues/1800", + "https://github.com/expressjs/express/pull/5539", + "https://github.com/expressjs/express/commit/0b746953c4bd8e377123527db11f9cd866e39f94", + "https://github.com/expressjs/express/commit/0867302ddbde0e9463d0564fea5861feb708c2dd", + "https://github.com/advisories/GHSA-rv95-896h-c2vc", + "https://expressjs.com/en/4x/api.html#res.location", + "https://nvd.nist.gov/vuln/detail/CVE-2024-29041", + "https://github.com/expressjs/express/security/advisories/GHSA-rv95-896h-c2vc" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-594935\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "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": "Medium", + "type": "security", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.11]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-75300", + "cves": [ + { + "cve": "CVE-2018-16487", + "cvss_v2_score": "6.8", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:P/I:P/A:P", + "cvss_v3_score": "5.6", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L" + } + ], + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2018-16487", + "https://www.npmjs.com/advisories/782", + "https://security.netapp.com/advisory/ntap-20190919-0004/", + "https://github.com/advisories/GHSA-4xc9-xhrj-v574", + "https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad", + "https://security.netapp.com/advisory/ntap-20190919-0004", + "https://hackerone.com/reports/380873" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-75300\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "Insufficient input validation in the Lodash library leads to prototype pollution.", + "full_description": "The [Lodash](https://lodash.com/) library is an open-source JavaScript project that simplifies operations on string, arrays, numbers, and other objects. It is widely used in connected devices. \n\nThe `merge`, `mergeWith`, and `defaultsDeep` methods in Lodash are vulnerable to [prototype pollution](https://shieldfy.io/security-wiki/prototype-pollution/introduction-to-prototype-pollution/). Attackers can exploit this vulnerability by specifying a crafted `sources` parameter to any of these methods, which can modify the prototype properties of the `Object`, `Function`, `Array`, `String`, `Number`, and `Boolean` objects. A public [exploit](https://hackerone.com/reports/380873) exists which performs the prototype pollution with an arbitrary key and value.\n\nThe library implementation has a bug in the `safeGet()` function in the `lodash.js` module that allows for adding or modifying `prototype` properties of various objects. The official [solution](https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad) fixes the bug by explicitly forbidding the addition or modification of `prototype` properties.\n\nA related CVE (CVE-2018-3721) covers the same issue prior to Lodash version 4.17.5, but the fix for that was incomplete.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find remote input that propagates into one of the following methods - \n* `merge` - 2nd argument\n* `mergeWith` - 2nd argument\n* `defaultsDeep` - 2nd argument", + "is_positive": true + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "A public PoC demonstrated exploitation by injecting an attacker controlled key and value into the prototype" + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." + } + }, + { + "summary": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", + "severity": "Critical", + "type": "security", + "components": { + "npm://ejs:3.1.6": { + "fixed_versions": [ + "[3.1.7]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://ejs:3.1.6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-209002", + "cves": [ + { + "cve": "CVE-2022-29078", + "cvss_v2_score": "7.5", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://github.com/mde/ejs/commit/15ee698583c98dadc456639d6245580d17a24baf", + "https://eslam.io/posts/ejs-server-side-template-injection-rce/", + "https://security.netapp.com/advisory/ntap-20220804-0001", + "https://github.com/mde/ejs/releases", + "https://nvd.nist.gov/vuln/detail/CVE-2022-29078", + "https://eslam.io/posts/ejs-server-side-template-injection-rce", + "https://github.com/mde/ejs", + "https://security.netapp.com/advisory/ntap-20220804-0001/" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-209002\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "Insufficient input validation in EJS enables attackers to perform template injection when attacker can control the rendering options.", + "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to perform template injection on the `opts.outputFunctionName` variable, since the variable is injected into the template body without any escaping. Although it is unlikely that the attacker can directly control the `outputFunctionName` property, it is possible that it can be influenced in conjunction with a prototype pollution vulnerability.\n\nOnce template injection is achieved, the attacker can immediately perform remote code execution since the template engine (EJS) allows executing arbitrary JavaScript code.\n\nExample of a vulnerable Node.js application -\n```js\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst lodash = require('lodash');\nconst ejs = require('ejs');\n\nconst app = express();\n\napp\n .use(bodyParser.urlencoded({extended: true}))\n .use(bodyParser.json());\n\napp.set('views', './');\napp.set('view engine', 'ejs');\n\napp.get(\"/\", (req, res) =\u003e {\n res.render('index');\n});\n\napp.post(\"/\", (req, res) =\u003e {\n let data = {};\n let input = JSON.parse(req.body.content);\n lodash.defaultsDeep(data, input);\n res.json({message: \"OK\"});\n});\n\nlet server = app.listen(8086, '0.0.0.0', function() {\n console.log('Listening on port %d', server.address().port);\n});\n```\n\nExploiting the above example for RCE -\n`curl 127.0.0.1:8086 -v --data 'content={\"constructor\": {\"prototype\": {\"outputFunctionName\": \"a; return global.process.mainModule.constructor._load(\\\"child_process\\\").execSync(\\\"whoami\\\"); //\"}}}'\n`\n\nDue to the prototype pollution in the `lodash.defaultsDeep` call, an attacker can inject the `outputFunctionName` property with an arbitrary value. The chosen value executes an arbitrary process via the `child_process` module.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker has to find a way to get their malicious input to `opts.outputFunctionName`, which will usually require exploitation of a prototype pollution vulnerability somewhere else in the code. However, there could be cases where the attacker can pass malicious data to the render function directly because of design problems in other code using EJS.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "There are multiple examples of exploits for this vulnerability online." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Successful exploitation of this vulnerability leads to remote code execution." + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\nNote that this mitigation is supposed to stop any prototype pollution attacks which can allow an attacker to control the `opts.outputFunctionName` parameter indirectly.\n\nThe mitigation will not stop any (extremely unlikely) scenarios where the JavaScript code allows external input to directly affect `opts.outputFunctionName`." + } + }, + { + "summary": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", + "severity": "Medium", + "type": "security", + "components": { + "npm://ejs:3.1.6": { + "fixed_versions": [ + "[3.1.10]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://ejs:3.1.6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-599735", + "cves": [ + { + "cve": "CVE-2024-33883", + "cvss_v3_score": "4.0", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L" + } + ], + "references": [ + "https://security.netapp.com/advisory/ntap-20240605-0003/", + "https://security.netapp.com/advisory/ntap-20240605-0003", + "https://github.com/mde/ejs/commit/e469741dca7df2eb400199e1cdb74621e3f89aa5", + "https://github.com/mde/ejs/compare/v3.1.9...v3.1.10", + "https://github.com/advisories/GHSA-ghr5-ch3p-vcr6", + "https://nvd.nist.gov/vuln/detail/CVE-2024-33883" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-599735\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "Insufficient input validation in EJS may lead to prototype pollution.", + "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as `EJS`, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nA prototype pollution gadget within the EJS template engine could potentially be leveraged by attackers to achieve remote code execution or DoS via prototype pollution.\n\n```\nfunction Template(text, opts) {\n opts = opts || utils.createNullProtoObjWherePossible();\n```\n\nWhen checking for the presence of a property within an object variable, the lookup scope isn't explicitly defined. In JavaScript, the absence of a defined lookup scope prompts a search up to the root prototype (`Object.prototype`). This could potentially be under the control of an attacker if another prototype pollution vulnerability is present within the application.\n\nIf the application server is using the EJS as the backend template engine, and there is another prototype pollution vulnerability in the application, then the attacker could leverage the found gadgets in the EJS template engine to escalate the prototype pollution to remote code execution or DoS.\n\nThe following code will execute a command on the server by polluting `opts.escapeFunction`:\n \n```\nconst express = require('express');\nconst app = express();\nconst port = 8008;\nconst ejs = require('ejs');\n\n// Set EJS as the view engine\napp.set('view engine', 'ejs');\n\napp.get('/', (req, res) =\u003e {\n \n const data = {title: 'Welcome', message: 'Hello'};\n\n // Sample EJS template string\n const templateString = `\u003chtml\u003e\u003chead\u003e\u003ctitle\u003e\u003c%= title %\u003e\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003ch1\u003e\u003c%= message %\u003e\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e`;\n\n const { exec } = require('child_process');\n\n function myFunc() {\n exec('bash -c \"echo 123\"', (error, stdout, stderr) =\u003e {\n if (error) {\n console.error(`exec error: ${error}`);\n return;\n }\n if (stderr){\n console.log(`stderr : ${stderr}`);\n return;\n }\n // Handle success\n console.log(`Command executed successfully. Output: ${stdout}`);\n });\n }\n\n const options = {client:false};\n\n Object.prototype.escapeFunction = myFunc;\n \n const compiledTemplate = ejs.compile(templateString, options);\n const renderedHtml = compiledTemplate(data);\n res.send(renderedHtml);\n});\n\n// Start the server\napp.listen(port, () =\u003e {\n console.log(`Server is running on http://localhost:${port}`);\n});\n```", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "Attackers can only leverage this vulnerability when the application server is using the EJS as the backend template engine. Moreover, there must be a second prototype pollution vulnerability in the application.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "CVSS does not take into account the unlikely prerequisites necessary for exploitation.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "A prototype pollution attack allows the attacker to inject new properties into all JavaScript objects.\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable." + } + ] + } + }, + { + "summary": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", + "severity": "Critical", + "type": "security", + "components": { + "npm://ejs:3.1.6": { + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://ejs:3.1.6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-520200", + "cves": [ + { + "cve": "CVE-2023-29827", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2023-29827", + "https://github.com/mde/ejs/issues/720", + "https://github.com/mde/ejs/blob/main/SECURITY.md#out-of-scope-vulnerabilities" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-520200\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "Insufficient input validation can lead to template injection in ejs when attackers can control both the rendered template and rendering options.", + "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to bypass ejs' template injection restrictions, by abusing the `closeDelimiter` rendering option, in the case when -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\n\nThe vulnerability was **rightfully disputed** due to the fact that a vulnerable configuration is extremely unlikely to exist in any real-world setup. As such, the maintainers will not provide a fix for this (non-)issue.\n\nExample of a vulnerable application -\n```js\nconst express = require('express')\nconst app = express()\nconst port = 3000\n\napp.set('view engine', 'ejs');\n\napp.get('/page', (req,res) =\u003e {\n res.render('page', req.query); // OPTS (2nd parameter) IS ATTACKER-CONTROLLED\n})\n\napp.listen(port, () =\u003e {\n console.log(\"Example app listening on port ${port}\")\n})\n```\n\nContents of `page.ejs` (very unlikely to be attacker controlled) -\n```js\n%%1\");process.mainModule.require('child_process').execSync('calc');//\n```\n\nIn this case, sending `closeDelimiter` with the same malicious code that already exists at `page.ejs` will trigger the injection -\n`http://127.0.0.1:3000/page?settings[view%20options][closeDelimiter]=1\")%3bprocess.mainModule.require('child_process').execSync('calc')%3b//`", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS does not take into account the rarity of a vulnerable configuration to exist", + "is_positive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The vulnerability can be exploited only under the following conditions -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\nThis vulnerable configuration is extremely unlikely to exist in any real-world setup.", + "is_positive": true + }, + { + "name": "The issue has been disputed by the vendor", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "Published exploit demonstrates template injection" + } + ] + } + }, + { + "summary": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", + "severity": "Critical", + "type": "security", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.12]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-85679", + "cves": [ + { + "cve": "CVE-2019-10744", + "cvss_v2_score": "6.4", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:P/A:P", + "cvss_v3_score": "9.1", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H" + } + ], + "references": [ + "https://www.npmjs.com/advisories/1065", + "https://github.com/lodash/lodash/pull/4336", + "https://www.oracle.com/security-alerts/cpujan2021.html", + "https://security.netapp.com/advisory/ntap-20191004-0005/", + "https://snyk.io/vuln/SNYK-JS-LODASH-450202", + "https://support.f5.com/csp/article/K47105354?utm_source=f5support\u0026amp;utm_medium=RSS", + "https://access.redhat.com/errata/RHSA-2019:3024", + "https://www.oracle.com/security-alerts/cpuoct2020.html", + "https://support.f5.com/csp/article/K47105354?utm_source=f5support\u0026amp%3Butm_medium=RSS", + "https://github.com/advisories/GHSA-jf85-cpcp-j695", + "https://nvd.nist.gov/vuln/detail/CVE-2019-10744" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-85679\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "Insufficient input validation in lodash defaultsDeep() leads to prototype pollution.", + "full_description": "[lodash](https://www.npmjs.com/package/lodash) is a modern JavaScript utility library delivering modularity, performance, \u0026 extras.\n\nThe function `defaultsDeep` was found to be vulnerable to prototype pollution, when accepting arbitrary source objects from untrusted input\n\nExample of code vulnerable to this issue - \n```js\nconst lodash = require('lodash'); \nconst evilsrc = {constructor: {prototype: {evilkey: \"evilvalue\"}}};\nlodash.defaultsDeep({}, evilsrc)\n```", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "A public PoC demonstrates exploitation of this issue" + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find remote input that propagates into the `defaultsDeep` method (2nd arg)", + "is_positive": true + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." + } + }, + { + "summary": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", + "severity": "Medium", + "type": "security", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.11]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-85049", + "cves": [ + { + "cve": "CVE-2019-1010266", + "cvss_v2_score": "4.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:S/C:N/I:N/A:P", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2019-1010266", + "https://github.com/lodash/lodash/wiki/Changelog", + "https://snyk.io/vuln/SNYK-JS-LODASH-73639", + "https://security.netapp.com/advisory/ntap-20190919-0004", + "https://security.netapp.com/advisory/ntap-20190919-0004/", + "https://github.com/lodash/lodash/issues/3359", + "https://github.com/lodash/lodash/commit/5c08f18d365b64063bfbfa686cbb97cdd6267347" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-85049\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", + "severity": "Medium", + "type": "security", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.21]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-140562", + "cves": [ + { + "cve": "CVE-2020-28500", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L" + } + ], + "references": [ + "https://cert-portal.siemens.com/productcert/pdf/ssa-637483.pdf", + "https://github.com/lodash/lodash/commit/c4847ebe7d14540bb28a8b932a9ce1b9ecbfee1a", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARS-1074894", + "https://github.com/lodash/lodash/blob/npm/trimEnd.js%23L8", + "https://security.netapp.com/advisory/ntap-20210312-0006/", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1074893", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWER-1074892", + "https://www.oracle.com//security-alerts/cpujul2021.html", + "https://www.oracle.com/security-alerts/cpuoct2021.html", + "https://nvd.nist.gov/vuln/detail/CVE-2020-28500", + "https://www.oracle.com/security-alerts/cpujul2022.html", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWERGITHUBLODASH-1074895", + "https://github.com/lodash/lodash/pull/5065/commits/02906b8191d3c100c193fe6f7b27d1c40f200bb7", + "https://www.oracle.com/security-alerts/cpujan2022.html", + "https://github.com/advisories/GHSA-29mw-wpgm-hmr9", + "https://github.com/lodash/lodash/pull/5065", + "https://snyk.io/vuln/SNYK-JAVA-ORGFUJIONWEBJARS-1074896", + "https://snyk.io/vuln/SNYK-JS-LODASH-1018905" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-140562\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "ReDoS in lodash could lead to a denial of service when handling untrusted strings.", + "full_description": "JavaScript-based applications that use [lodash](https://github.com/lodash/lodash) and specifically the [_.toNumber](https://lodash.com/docs/4.17.15#toNumber), [_.trim](https://lodash.com/docs/4.17.15#trim) and [_.trimEnd](https://lodash.com/docs/4.17.15#trimEnd) functions, could be vulnerable to DoS (Denial of Service) through a faulty regular expression that introduces a ReDoS (Regular Expression DoS) vulnerability. This vulnerability is only triggered if untrusted user input flows into these vulnerable functions and the attacker can supply arbitrary long strings (over 50kB) that contain whitespaces. \n\nOn a modern Core i7-based system, calling the vulnerable functions with a 50kB string could take between 2 to 3 seconds to execute and 4.5 minutes for a longer 500kB string. The fix improved the regular expression performance so it took only a few milliseconds on the same Core i7-based system. This vulnerability is easily exploitable as all is required is to build a string that triggers it as can be seen in this PoC reproducing code - \n\n```js\nvar untrusted_user_input_50k = \"a\" + ' '.repeat(50000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_50k); // should take a few seconds to run\nvar untrusted_user_input_500k = \"a\" + ' '.repeat(500000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_500k); // should take a few minutes to run\n```", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "Public exploit demonstrated ReDoS" + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "Exploitation depends on parsing user input by the `.toNumber`, `.trim` or `.trimEnd` `lodash` functions, and requires the input to contain whitespaces and be very long (over 50KB)", + "is_positive": true + } + ], + "remediation": "##### Deployment mitigations\n\nTrim untrusted strings based on size before providing it to the vulnerable functions by using the `substring` function to with a fixed maximum size like so - ```js untrusted_user_input.substring(0, max_string_size_less_than_50kB); ```" + } + }, + { + "summary": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", + "severity": "High", + "type": "security", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.21]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-140575", + "cves": [ + { + "cve": "CVE-2021-23337", + "cvss_v2_score": "6.5", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:S/C:P/I:P/A:P", + "cvss_v3_score": "7.2", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1074929", + "https://security.netapp.com/advisory/ntap-20210312-0006/", + "https://snyk.io/vuln/SNYK-JS-LODASH-1040724", + "https://security.netapp.com/advisory/ntap-20210312-0006", + "https://www.oracle.com/security-alerts/cpujan2022.html", + "https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c", + "https://cert-portal.siemens.com/productcert/pdf/ssa-637483.pdf", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWER-1074928", + "https://www.oracle.com/security-alerts/cpuoct2021.html", + "https://snyk.io/vuln/SNYK-JAVA-ORGFUJIONWEBJARS-1074932", + "https://github.com/lodash/lodash/blob/ddfd9b11a0126db2302cb70ec9973b66baec0975/lodash.js%23L14851", + "https://github.com/advisories/GHSA-35jh-r3h4-6jhm", + "https://www.oracle.com/security-alerts/cpujul2022.html", + "https://www.oracle.com//security-alerts/cpujul2021.html", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARS-1074930", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWERGITHUBLODASH-1074931", + "https://nvd.nist.gov/vuln/detail/CVE-2021-23337", + "https://github.com/lodash/lodash/blob/ddfd9b11a0126db2302cb70ec9973b66baec0975/lodash.js#L14851" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-140575\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "Improper sanitization in the lodash template function leads to JavaScript code injection through the options argument.", + "full_description": "JavaScript-based applications (both frontend and backend) that use the [template function](https://lodash.com/docs/4.17.15#template) -`_.template([string=''], [options={}])` from the [lodash](https://lodash.com/) utility library and provide the `options` argument (specifically the `variable` option) from untrusted user input, are vulnerable to JavaScript code injection. This issue can be easily exploited, and an exploitation example is [publicly available](https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c#diff-a561630bb56b82342bc66697aee2ad96efddcbc9d150665abd6fb7ecb7c0ab2fR22303) in the fix tests that was introduced in version 4.17.21 - \n```js\nlodash.template('', { variable: '){console.log(process.env)}; with(obj' })()\n```", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "It is highly unlikely that a JS program will accept arbitrary remote input into the template's `options` argument", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must find remote input that propagates into the `options` argument of a `template` call", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Leads to remote code execution through JS code injection" + }, + { + "name": "The issue has an exploit published", + "description": "Published exploit demonstrates arbitrary JS code execution" + } + ] + } + } + ], + "vulnerabilities": [ + { + "cves": [ + { + "cve": "CVE-2024-39249" + } + ], + "summary": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", + "severity": "Unknown", + "components": { + "npm://async:3.2.4": { + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://ejs:3.1.6" + }, + { + "component_id": "npm://jake:10.8.7" + }, + { + "component_id": "npm://async:3.2.4" + } + ] + ] + } + }, + "issue_id": "XRAY-609848", + "references": [ + "https://github.com/zunak/CVE-2024-39249", + "https://github.com/caolan/async/blob/v3.2.5/lib/autoInject.js#L41", + "https://nvd.nist.gov/vuln/detail/CVE-2024-39249", + "https://github.com/caolan/async/blob/v3.2.5/lib/autoInject.js#L6", + "https://github.com/caolan/async/issues/1975#issuecomment-2204528153", + "https://github.com/zunak/CVE-2024-39249/issues/1" + ], + "extended_information": { + "short_description": "ReDoS in Async may lead to denial of service while parsing malformed source code.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The reported CVSS does not reflect the severity of the vulnerability.", + "is_positive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "To exploit this issue an attacker must change the source code of the application. In cases where an attacker can already modify (or fully control) the source code, the attacker can immediately achieve arbitrary code execution - thus this issue has almost no security impact.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "A proof-of-concept has been published in the advisory." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The issue requires the use of the `async.autoInject` function to be vulnerable.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2020-8203", + "cvss_v2_score": "5.8", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:P/A:P", + "cvss_v3_score": "7.4", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:H", + "cwe": [ + "CWE-770", + "CWE-1321" + ], + "cwe_details": { + "CWE-1321": { + "name": "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')", + "description": "The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype." + }, + "CWE-770": { + "name": "Allocation of Resources Without Limits or Throttling", + "description": "The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor." + } + } + } + ], + "summary": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", + "severity": "High", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.19]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "issue_id": "XRAY-114089", + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2020-8203", + "https://www.oracle.com/security-alerts/cpuapr2022.html", + "https://hackerone.com/reports/864701", + "https://hackerone.com/reports/712065", + "https://github.com/advisories/GHSA-p6mc-m468-83gw", + "https://www.oracle.com//security-alerts/cpujul2021.html", + "https://github.com/lodash/lodash/issues/4744", + "https://www.oracle.com/security-alerts/cpuApr2021.html", + "https://github.com/github/advisory-database/pull/2884", + "https://www.oracle.com/security-alerts/cpujan2022.html", + "https://github.com/lodash/lodash/commit/c84fe82760fb2d3e03a63379b297a1cc1a2fce12", + "https://security.netapp.com/advisory/ntap-20200724-0006/", + "https://web.archive.org/web/20210914001339/https://github.com/lodash/lodash/issues/4744", + "https://www.oracle.com/security-alerts/cpuoct2021.html", + "https://github.com/lodash/lodash/issues/4874", + "https://github.com/lodash/lodash/wiki/Changelog#v41719" + ], + "extended_information": { + "short_description": "Prototype pollution in lodash object merging and zipping functions leads to code injection.", + "full_description": "[lodash](https://lodash.com/) is a JavaScript library which provides utility functions for common programming tasks.\n\nJavaScript frontend and Node.js-based backend applications that merge or zip objects using the lodash functions `mergeWith`, `merge` and `zipObjectDeep` are vulnerable to [prototype pollution](https://medium.com/node-modules/what-is-prototype-pollution-and-why-is-it-such-a-big-deal-2dd8d89a93c) if one or more of the objects it receives as arguments are obtained from user input. \nAn attacker controlling this input given to the vulnerable functions can inject properties to JavaScript special objects such as [Object.prototype](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes) from which all JavaScript objects inherit properties and methods. Any change on `Object.prototype` properties will then propagate through the prototype chain inheritance to all of the objects in a JavaScript application. This in turn would allow an attacker to add new properties or modify existing properties which will have application specific implications that could lead to DoS (denial of service), authentication bypass, privilege escalation and even RCE (remote code execution) in [some cases](https://youtu.be/LUsiFV3dsK8?t=1152). \nAs an example for privilege escalation, consider a JavaScript application that has a `user` object which has a Boolean property of `user.isAdmin` which is used to decide which actions the user may take. If an attacker can modify or add the `isAdmin` property through prototype pollution, it can escalate the privileges of its own user to those of an admin. \nAs exploitation is usually application specific, successful exploitation is much more likely if an attacker have access to the JavaScript application code. As such, frontend applications are more vulnerable to this vulnerability than Node.js backend applications.", + "jfrog_research_severity": "Critical", + "jfrog_research_severity_reasons": [ + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "is_positive": true + }, + { + "name": "The issue can be exploited by attackers over the network" + }, + { + "name": "The issue is trivial to exploit and does not require a published writeup or PoC" + } + ], + "remediation": "##### Deployment mitigations\n\nAs general guidelines against prototype pollution, first consider not merging objects originating from user input or using a Map structure instead of an object. If merging objects is needed, look into creating objects without a prototype with `Object.create(null)` or into freezing `Object.prototype` with `Object.freeze()`. Finally, it is always best to perform input validation with a a [JSON schema validator](https://github.com/ajv-validator/ajv), which could mitigate this issue entirely in many cases." + } + }, + { + "cves": [ + { + "cve": "CVE-2019-10744", + "cvss_v2_score": "6.4", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:P/A:P", + "cvss_v3_score": "9.1", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H", + "cwe": [ + "CWE-1321", + "CWE-20" + ], + "cwe_details": { + "CWE-1321": { + "name": "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')", + "description": "The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype." + }, + "CWE-20": { + "name": "Improper Input Validation", + "description": "The product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "6" + } + ] + } + } + } + ], + "summary": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", + "severity": "Critical", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.12]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "issue_id": "XRAY-85679", + "references": [ + "https://www.npmjs.com/advisories/1065", + "https://github.com/lodash/lodash/pull/4336", + "https://www.oracle.com/security-alerts/cpujan2021.html", + "https://security.netapp.com/advisory/ntap-20191004-0005/", + "https://snyk.io/vuln/SNYK-JS-LODASH-450202", + "https://support.f5.com/csp/article/K47105354?utm_source=f5support\u0026amp;utm_medium=RSS", + "https://access.redhat.com/errata/RHSA-2019:3024", + "https://www.oracle.com/security-alerts/cpuoct2020.html", + "https://support.f5.com/csp/article/K47105354?utm_source=f5support\u0026amp%3Butm_medium=RSS", + "https://github.com/advisories/GHSA-jf85-cpcp-j695", + "https://nvd.nist.gov/vuln/detail/CVE-2019-10744" + ], + "extended_information": { + "short_description": "Insufficient input validation in lodash defaultsDeep() leads to prototype pollution.", + "full_description": "[lodash](https://www.npmjs.com/package/lodash) is a modern JavaScript utility library delivering modularity, performance, \u0026 extras.\n\nThe function `defaultsDeep` was found to be vulnerable to prototype pollution, when accepting arbitrary source objects from untrusted input\n\nExample of code vulnerable to this issue - \n```js\nconst lodash = require('lodash'); \nconst evilsrc = {constructor: {prototype: {evilkey: \"evilvalue\"}}};\nlodash.defaultsDeep({}, evilsrc)\n```", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "A public PoC demonstrates exploitation of this issue" + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find remote input that propagates into the `defaultsDeep` method (2nd arg)", + "is_positive": true + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." + } + }, + { + "cves": [ + { + "cve": "CVE-2019-1010266", + "cvss_v2_score": "4.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:S/C:N/I:N/A:P", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-400", + "CWE-770" + ], + "cwe_details": { + "CWE-400": { + "name": "Uncontrolled Resource Consumption", + "description": "The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources." + }, + "CWE-770": { + "name": "Allocation of Resources Without Limits or Throttling", + "description": "The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor." + } + } + } + ], + "summary": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", + "severity": "Medium", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.11]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "issue_id": "XRAY-85049", + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2019-1010266", + "https://github.com/lodash/lodash/wiki/Changelog", + "https://snyk.io/vuln/SNYK-JS-LODASH-73639", + "https://security.netapp.com/advisory/ntap-20190919-0004", + "https://security.netapp.com/advisory/ntap-20190919-0004/", + "https://github.com/lodash/lodash/issues/3359", + "https://github.com/lodash/lodash/commit/5c08f18d365b64063bfbfa686cbb97cdd6267347" + ] + }, + { + "cves": [ + { + "cve": "CVE-2020-28500", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "cwe": [ + "CWE-400", + "CWE-1333", + "NVD-CWE-Other" + ], + "cwe_details": { + "CWE-1333": { + "name": "Inefficient Regular Expression Complexity", + "description": "The product uses a regular expression with an inefficient, possibly exponential worst-case computational complexity that consumes excessive CPU cycles." + }, + "CWE-400": { + "name": "Uncontrolled Resource Consumption", + "description": "The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources." + } + } + } + ], + "summary": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", + "severity": "Medium", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.21]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "issue_id": "XRAY-140562", + "references": [ + "https://cert-portal.siemens.com/productcert/pdf/ssa-637483.pdf", + "https://github.com/lodash/lodash/commit/c4847ebe7d14540bb28a8b932a9ce1b9ecbfee1a", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARS-1074894", + "https://github.com/lodash/lodash/blob/npm/trimEnd.js%23L8", + "https://security.netapp.com/advisory/ntap-20210312-0006/", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1074893", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWER-1074892", + "https://www.oracle.com//security-alerts/cpujul2021.html", + "https://www.oracle.com/security-alerts/cpuoct2021.html", + "https://nvd.nist.gov/vuln/detail/CVE-2020-28500", + "https://www.oracle.com/security-alerts/cpujul2022.html", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWERGITHUBLODASH-1074895", + "https://github.com/lodash/lodash/pull/5065/commits/02906b8191d3c100c193fe6f7b27d1c40f200bb7", + "https://www.oracle.com/security-alerts/cpujan2022.html", + "https://github.com/advisories/GHSA-29mw-wpgm-hmr9", + "https://github.com/lodash/lodash/pull/5065", + "https://snyk.io/vuln/SNYK-JAVA-ORGFUJIONWEBJARS-1074896", + "https://snyk.io/vuln/SNYK-JS-LODASH-1018905" + ], + "extended_information": { + "short_description": "ReDoS in lodash could lead to a denial of service when handling untrusted strings.", + "full_description": "JavaScript-based applications that use [lodash](https://github.com/lodash/lodash) and specifically the [_.toNumber](https://lodash.com/docs/4.17.15#toNumber), [_.trim](https://lodash.com/docs/4.17.15#trim) and [_.trimEnd](https://lodash.com/docs/4.17.15#trimEnd) functions, could be vulnerable to DoS (Denial of Service) through a faulty regular expression that introduces a ReDoS (Regular Expression DoS) vulnerability. This vulnerability is only triggered if untrusted user input flows into these vulnerable functions and the attacker can supply arbitrary long strings (over 50kB) that contain whitespaces. \n\nOn a modern Core i7-based system, calling the vulnerable functions with a 50kB string could take between 2 to 3 seconds to execute and 4.5 minutes for a longer 500kB string. The fix improved the regular expression performance so it took only a few milliseconds on the same Core i7-based system. This vulnerability is easily exploitable as all is required is to build a string that triggers it as can be seen in this PoC reproducing code - \n\n```js\nvar untrusted_user_input_50k = \"a\" + ' '.repeat(50000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_50k); // should take a few seconds to run\nvar untrusted_user_input_500k = \"a\" + ' '.repeat(500000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_500k); // should take a few minutes to run\n```", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "Public exploit demonstrated ReDoS" + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "Exploitation depends on parsing user input by the `.toNumber`, `.trim` or `.trimEnd` `lodash` functions, and requires the input to contain whitespaces and be very long (over 50KB)", + "is_positive": true + } + ], + "remediation": "##### Deployment mitigations\n\nTrim untrusted strings based on size before providing it to the vulnerable functions by using the `substring` function to with a fixed maximum size like so - ```js untrusted_user_input.substring(0, max_string_size_less_than_50kB); ```" + } + }, + { + "cves": [ + { + "cve": "CVE-2018-3721", + "cvss_v2_score": "4.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:S/C:N/I:P/A:N", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N", + "cwe": [ + "CWE-1321", + "CWE-471" + ], + "cwe_details": { + "CWE-1321": { + "name": "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')", + "description": "The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype." + }, + "CWE-471": { + "name": "Modification of Assumed-Immutable Data (MAID)", + "description": "The product does not properly protect an assumed-immutable element from being modified by an attacker." + } + } + } + ], + "summary": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", + "severity": "Medium", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.5]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "issue_id": "XRAY-72918", + "references": [ + "https://www.npmjs.com/advisories/577", + "https://hackerone.com/reports/310443", + "https://github.com/advisories/GHSA-fvqr-27wr-82fm", + "https://nvd.nist.gov/vuln/detail/CVE-2018-3721", + "https://security.netapp.com/advisory/ntap-20190919-0004", + "https://security.netapp.com/advisory/ntap-20190919-0004/", + "https://github.com/lodash/lodash/commit/d8e069cc3410082e44eb18fcf8e7f3d08ebe1d4a" + ] + }, + { + "cves": [ + { + "cve": "CVE-2021-23337", + "cvss_v2_score": "6.5", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:S/C:P/I:P/A:P", + "cvss_v3_score": "7.2", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-77", + "CWE-94" + ], + "cwe_details": { + "CWE-77": { + "name": "Improper Neutralization of Special Elements used in a Command ('Command Injection')", + "description": "The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "16" + } + ] + }, + "CWE-94": { + "name": "Improper Control of Generation of Code ('Code Injection')", + "description": "The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "23" + } + ] + } + } + } + ], + "summary": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", + "severity": "High", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.21]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "issue_id": "XRAY-140575", + "references": [ + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1074929", + "https://security.netapp.com/advisory/ntap-20210312-0006/", + "https://snyk.io/vuln/SNYK-JS-LODASH-1040724", + "https://security.netapp.com/advisory/ntap-20210312-0006", + "https://www.oracle.com/security-alerts/cpujan2022.html", + "https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c", + "https://cert-portal.siemens.com/productcert/pdf/ssa-637483.pdf", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWER-1074928", + "https://www.oracle.com/security-alerts/cpuoct2021.html", + "https://snyk.io/vuln/SNYK-JAVA-ORGFUJIONWEBJARS-1074932", + "https://github.com/lodash/lodash/blob/ddfd9b11a0126db2302cb70ec9973b66baec0975/lodash.js%23L14851", + "https://github.com/advisories/GHSA-35jh-r3h4-6jhm", + "https://www.oracle.com/security-alerts/cpujul2022.html", + "https://www.oracle.com//security-alerts/cpujul2021.html", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARS-1074930", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWERGITHUBLODASH-1074931", + "https://nvd.nist.gov/vuln/detail/CVE-2021-23337", + "https://github.com/lodash/lodash/blob/ddfd9b11a0126db2302cb70ec9973b66baec0975/lodash.js#L14851" + ], + "extended_information": { + "short_description": "Improper sanitization in the lodash template function leads to JavaScript code injection through the options argument.", + "full_description": "JavaScript-based applications (both frontend and backend) that use the [template function](https://lodash.com/docs/4.17.15#template) -`_.template([string=''], [options={}])` from the [lodash](https://lodash.com/) utility library and provide the `options` argument (specifically the `variable` option) from untrusted user input, are vulnerable to JavaScript code injection. This issue can be easily exploited, and an exploitation example is [publicly available](https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c#diff-a561630bb56b82342bc66697aee2ad96efddcbc9d150665abd6fb7ecb7c0ab2fR22303) in the fix tests that was introduced in version 4.17.21 - \n```js\nlodash.template('', { variable: '){console.log(process.env)}; with(obj' })()\n```", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "It is highly unlikely that a JS program will accept arbitrary remote input into the template's `options` argument", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must find remote input that propagates into the `options` argument of a `template` call", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Leads to remote code execution through JS code injection" + }, + { + "name": "The issue has an exploit published", + "description": "Published exploit demonstrates arbitrary JS code execution" + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2018-16487", + "cvss_v2_score": "6.8", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:P/I:P/A:P", + "cvss_v3_score": "5.6", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L", + "cwe": [ + "CWE-400", + "NVD-CWE-noinfo" + ], + "cwe_details": { + "CWE-400": { + "name": "Uncontrolled Resource Consumption", + "description": "The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources." + } + } + } + ], + "summary": "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": "Medium", + "components": { + "npm://lodash:4.17.0": { + "fixed_versions": [ + "[4.17.11]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://lodash:4.17.0" + } + ] + ] + } + }, + "issue_id": "XRAY-75300", + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2018-16487", + "https://www.npmjs.com/advisories/782", + "https://security.netapp.com/advisory/ntap-20190919-0004/", + "https://github.com/advisories/GHSA-4xc9-xhrj-v574", + "https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad", + "https://security.netapp.com/advisory/ntap-20190919-0004", + "https://hackerone.com/reports/380873" + ], + "extended_information": { + "short_description": "Insufficient input validation in the Lodash library leads to prototype pollution.", + "full_description": "The [Lodash](https://lodash.com/) library is an open-source JavaScript project that simplifies operations on string, arrays, numbers, and other objects. It is widely used in connected devices. \n\nThe `merge`, `mergeWith`, and `defaultsDeep` methods in Lodash are vulnerable to [prototype pollution](https://shieldfy.io/security-wiki/prototype-pollution/introduction-to-prototype-pollution/). Attackers can exploit this vulnerability by specifying a crafted `sources` parameter to any of these methods, which can modify the prototype properties of the `Object`, `Function`, `Array`, `String`, `Number`, and `Boolean` objects. A public [exploit](https://hackerone.com/reports/380873) exists which performs the prototype pollution with an arbitrary key and value.\n\nThe library implementation has a bug in the `safeGet()` function in the `lodash.js` module that allows for adding or modifying `prototype` properties of various objects. The official [solution](https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad) fixes the bug by explicitly forbidding the addition or modification of `prototype` properties.\n\nA related CVE (CVE-2018-3721) covers the same issue prior to Lodash version 4.17.5, but the fix for that was incomplete.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find remote input that propagates into one of the following methods - \n* `merge` - 2nd argument\n* `mergeWith` - 2nd argument\n* `defaultsDeep` - 2nd argument", + "is_positive": true + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "A public PoC demonstrated exploitation by injecting an attacker controlled key and value into the prototype" + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." + } + }, + { + "cves": [ + { + "cve": "CVE-2024-29041", + "cvss_v3_score": "6.1", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N", + "cwe": [ + "CWE-601", + "CWE-1286" + ], + "cwe_details": { + "CWE-1286": { + "name": "Improper Validation of Syntactic Correctness of Input", + "description": "The product receives input that is expected to be well-formed - i.e., to comply with a certain syntax - but it does not validate or incorrectly validates that the input complies with the syntax." + }, + "CWE-601": { + "name": "URL Redirection to Untrusted Site ('Open Redirect')", + "description": "A web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a Redirect. This simplifies phishing attacks." + } + } + } + ], + "summary": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", + "severity": "Medium", + "components": { + "npm://express:4.18.2": { + "fixed_versions": [ + "[4.19.2]", + "[5.0.0-beta.3]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://express:4.18.2" + } + ] + ] + } + }, + "issue_id": "XRAY-594935", + "references": [ + "https://github.com/koajs/koa/issues/1800", + "https://github.com/expressjs/express/pull/5539", + "https://github.com/expressjs/express/commit/0b746953c4bd8e377123527db11f9cd866e39f94", + "https://github.com/expressjs/express/commit/0867302ddbde0e9463d0564fea5861feb708c2dd", + "https://github.com/advisories/GHSA-rv95-896h-c2vc", + "https://expressjs.com/en/4x/api.html#res.location", + "https://nvd.nist.gov/vuln/detail/CVE-2024-29041", + "https://github.com/expressjs/express/security/advisories/GHSA-rv95-896h-c2vc" + ] + }, + { + "cves": [ + { + "cve": "CVE-2022-29078", + "cvss_v2_score": "7.5", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-94", + "CWE-74" + ], + "cwe_details": { + "CWE-74": { + "name": "Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')", + "description": "The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component." + }, + "CWE-94": { + "name": "Improper Control of Generation of Code ('Code Injection')", + "description": "The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "23" + } + ] + } + } + } + ], + "summary": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", + "severity": "Critical", + "components": { + "npm://ejs:3.1.6": { + "fixed_versions": [ + "[3.1.7]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://ejs:3.1.6" + } + ] + ] + } + }, + "issue_id": "XRAY-209002", + "references": [ + "https://github.com/mde/ejs/commit/15ee698583c98dadc456639d6245580d17a24baf", + "https://eslam.io/posts/ejs-server-side-template-injection-rce/", + "https://security.netapp.com/advisory/ntap-20220804-0001", + "https://github.com/mde/ejs/releases", + "https://nvd.nist.gov/vuln/detail/CVE-2022-29078", + "https://eslam.io/posts/ejs-server-side-template-injection-rce", + "https://github.com/mde/ejs", + "https://security.netapp.com/advisory/ntap-20220804-0001/" + ], + "extended_information": { + "short_description": "Insufficient input validation in EJS enables attackers to perform template injection when attacker can control the rendering options.", + "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to perform template injection on the `opts.outputFunctionName` variable, since the variable is injected into the template body without any escaping. Although it is unlikely that the attacker can directly control the `outputFunctionName` property, it is possible that it can be influenced in conjunction with a prototype pollution vulnerability.\n\nOnce template injection is achieved, the attacker can immediately perform remote code execution since the template engine (EJS) allows executing arbitrary JavaScript code.\n\nExample of a vulnerable Node.js application -\n```js\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst lodash = require('lodash');\nconst ejs = require('ejs');\n\nconst app = express();\n\napp\n .use(bodyParser.urlencoded({extended: true}))\n .use(bodyParser.json());\n\napp.set('views', './');\napp.set('view engine', 'ejs');\n\napp.get(\"/\", (req, res) =\u003e {\n res.render('index');\n});\n\napp.post(\"/\", (req, res) =\u003e {\n let data = {};\n let input = JSON.parse(req.body.content);\n lodash.defaultsDeep(data, input);\n res.json({message: \"OK\"});\n});\n\nlet server = app.listen(8086, '0.0.0.0', function() {\n console.log('Listening on port %d', server.address().port);\n});\n```\n\nExploiting the above example for RCE -\n`curl 127.0.0.1:8086 -v --data 'content={\"constructor\": {\"prototype\": {\"outputFunctionName\": \"a; return global.process.mainModule.constructor._load(\\\"child_process\\\").execSync(\\\"whoami\\\"); //\"}}}'\n`\n\nDue to the prototype pollution in the `lodash.defaultsDeep` call, an attacker can inject the `outputFunctionName` property with an arbitrary value. The chosen value executes an arbitrary process via the `child_process` module.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker has to find a way to get their malicious input to `opts.outputFunctionName`, which will usually require exploitation of a prototype pollution vulnerability somewhere else in the code. However, there could be cases where the attacker can pass malicious data to the render function directly because of design problems in other code using EJS.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "There are multiple examples of exploits for this vulnerability online." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Successful exploitation of this vulnerability leads to remote code execution." + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\nNote that this mitigation is supposed to stop any prototype pollution attacks which can allow an attacker to control the `opts.outputFunctionName` parameter indirectly.\n\nThe mitigation will not stop any (extremely unlikely) scenarios where the JavaScript code allows external input to directly affect `opts.outputFunctionName`." + } + }, + { + "cves": [ + { + "cve": "CVE-2024-33883", + "cvss_v3_score": "4.0", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "cwe": [ + "CWE-1321", + "CWE-693" + ], + "cwe_details": { + "CWE-1321": { + "name": "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')", + "description": "The product receives input from an upstream component that specifies attributes that are to be initialized or updated in an object, but it does not properly control modifications of attributes of the object prototype." + }, + "CWE-693": { + "name": "Protection Mechanism Failure", + "description": "The product does not use or incorrectly uses a protection mechanism that provides sufficient defense against directed attacks against the product." + } + } + } + ], + "summary": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", + "severity": "Medium", + "components": { + "npm://ejs:3.1.6": { + "fixed_versions": [ + "[3.1.10]" + ], + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://ejs:3.1.6" + } + ] + ] + } + }, + "issue_id": "XRAY-599735", + "references": [ + "https://security.netapp.com/advisory/ntap-20240605-0003/", + "https://security.netapp.com/advisory/ntap-20240605-0003", + "https://github.com/mde/ejs/commit/e469741dca7df2eb400199e1cdb74621e3f89aa5", + "https://github.com/mde/ejs/compare/v3.1.9...v3.1.10", + "https://github.com/advisories/GHSA-ghr5-ch3p-vcr6", + "https://nvd.nist.gov/vuln/detail/CVE-2024-33883" + ], + "extended_information": { + "short_description": "Insufficient input validation in EJS may lead to prototype pollution.", + "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as `EJS`, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nA prototype pollution gadget within the EJS template engine could potentially be leveraged by attackers to achieve remote code execution or DoS via prototype pollution.\n\n```\nfunction Template(text, opts) {\n opts = opts || utils.createNullProtoObjWherePossible();\n```\n\nWhen checking for the presence of a property within an object variable, the lookup scope isn't explicitly defined. In JavaScript, the absence of a defined lookup scope prompts a search up to the root prototype (`Object.prototype`). This could potentially be under the control of an attacker if another prototype pollution vulnerability is present within the application.\n\nIf the application server is using the EJS as the backend template engine, and there is another prototype pollution vulnerability in the application, then the attacker could leverage the found gadgets in the EJS template engine to escalate the prototype pollution to remote code execution or DoS.\n\nThe following code will execute a command on the server by polluting `opts.escapeFunction`:\n \n```\nconst express = require('express');\nconst app = express();\nconst port = 8008;\nconst ejs = require('ejs');\n\n// Set EJS as the view engine\napp.set('view engine', 'ejs');\n\napp.get('/', (req, res) =\u003e {\n \n const data = {title: 'Welcome', message: 'Hello'};\n\n // Sample EJS template string\n const templateString = `\u003chtml\u003e\u003chead\u003e\u003ctitle\u003e\u003c%= title %\u003e\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003ch1\u003e\u003c%= message %\u003e\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e`;\n\n const { exec } = require('child_process');\n\n function myFunc() {\n exec('bash -c \"echo 123\"', (error, stdout, stderr) =\u003e {\n if (error) {\n console.error(`exec error: ${error}`);\n return;\n }\n if (stderr){\n console.log(`stderr : ${stderr}`);\n return;\n }\n // Handle success\n console.log(`Command executed successfully. Output: ${stdout}`);\n });\n }\n\n const options = {client:false};\n\n Object.prototype.escapeFunction = myFunc;\n \n const compiledTemplate = ejs.compile(templateString, options);\n const renderedHtml = compiledTemplate(data);\n res.send(renderedHtml);\n});\n\n// Start the server\napp.listen(port, () =\u003e {\n console.log(`Server is running on http://localhost:${port}`);\n});\n```", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "Attackers can only leverage this vulnerability when the application server is using the EJS as the backend template engine. Moreover, there must be a second prototype pollution vulnerability in the application.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "CVSS does not take into account the unlikely prerequisites necessary for exploitation.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "A prototype pollution attack allows the attacker to inject new properties into all JavaScript objects.\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable." + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-29827", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-74" + ], + "cwe_details": { + "CWE-74": { + "name": "Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')", + "description": "The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component." + } + } + } + ], + "summary": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", + "severity": "Critical", + "components": { + "npm://ejs:3.1.6": { + "impact_paths": [ + [ + { + "component_id": "npm://froghome:1.0.0" + }, + { + "component_id": "npm://ejs:3.1.6" + } + ] + ] + } + }, + "issue_id": "XRAY-520200", + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2023-29827", + "https://github.com/mde/ejs/issues/720", + "https://github.com/mde/ejs/blob/main/SECURITY.md#out-of-scope-vulnerabilities" + ], + "extended_information": { + "short_description": "Insufficient input validation can lead to template injection in ejs when attackers can control both the rendered template and rendering options.", + "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to bypass ejs' template injection restrictions, by abusing the `closeDelimiter` rendering option, in the case when -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\n\nThe vulnerability was **rightfully disputed** due to the fact that a vulnerable configuration is extremely unlikely to exist in any real-world setup. As such, the maintainers will not provide a fix for this (non-)issue.\n\nExample of a vulnerable application -\n```js\nconst express = require('express')\nconst app = express()\nconst port = 3000\n\napp.set('view engine', 'ejs');\n\napp.get('/page', (req,res) =\u003e {\n res.render('page', req.query); // OPTS (2nd parameter) IS ATTACKER-CONTROLLED\n})\n\napp.listen(port, () =\u003e {\n console.log(\"Example app listening on port ${port}\")\n})\n```\n\nContents of `page.ejs` (very unlikely to be attacker controlled) -\n```js\n%%1\");process.mainModule.require('child_process').execSync('calc');//\n```\n\nIn this case, sending `closeDelimiter` with the same malicious code that already exists at `page.ejs` will trigger the injection -\n`http://127.0.0.1:3000/page?settings[view%20options][closeDelimiter]=1\")%3bprocess.mainModule.require('child_process').execSync('calc')%3b//`", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS does not take into account the rarity of a vulnerable configuration to exist", + "is_positive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The vulnerability can be exploited only under the following conditions -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\nThis vulnerable configuration is extremely unlikely to exist in any real-world setup.", + "is_positive": true + }, + { + "name": "The issue has been disputed by the vendor", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "Published exploit demonstrates template injection" + } + ] + } + } + ], + "component_id": "root", + "package_type": "generic", + "status": "completed" + } + ] + }, + "jas_scans": { + "contextual_analysis": [ + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Applicability Scanner", + "rules": [ + { + "id": "applic_CVE-2018-16487", + "name": "CVE-2018-16487", + "shortDescription": { + "text": "Scanner for CVE-2018-16487" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2019-10744", + "name": "CVE-2019-10744", + "shortDescription": { + "text": "Scanner for CVE-2019-10744" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2020-28500", + "name": "CVE-2020-28500", + "shortDescription": { + "text": "Scanner for CVE-2020-28500" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument.", + "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2020-8203", + "name": "CVE-2020-8203", + "shortDescription": { + "text": "Scanner for CVE-2020-8203" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2021-23337", + "name": "CVE-2021-23337", + "shortDescription": { + "text": "Scanner for CVE-2021-23337" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument.", + "markdown": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2022-29078", + "name": "CVE-2022-29078", + "shortDescription": { + "text": "Scanner for CVE-2022-29078" + }, + "fullDescription": { + "text": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "markdown": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-33883", + "name": "CVE-2024-33883", + "shortDescription": { + "text": "Scanner for CVE-2024-33883" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `ejs.compile()` is called.", + "markdown": "The scanner checks whether the vulnerable function `ejs.compile()` is called." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-29827", + "name": "CVE-2023-29827", + "shortDescription": { + "text": "Scanner for CVE-2023-29827" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`", + "markdown": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2018-3721", + "name": "CVE-2018-3721", + "shortDescription": { + "text": "Scanner for uncovered CVE-2018-3721" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2019-1010266", + "name": "CVE-2019-1010266", + "shortDescription": { + "text": "Scanner for uncovered CVE-2019-1010266" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-39249", + "name": "CVE-2024-39249", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-39249" + }, + "fullDescription": { + "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", + "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + }, + "properties": { + "applicability": "not_covered", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-29041", + "name": "CVE-2024-29041", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-29041" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-39249", + "name": "CVE-2024-39249", + "shortDescription": { + "text": "Scanner for indirect dependency CVE-2024-39249" + }, + "fullDescription": { + "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code.", + "markdown": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + }, + "properties": { + "applicability": "not_applicable" + } + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "analyzerManager/jas_scanner/jas_scanner", + "scan", + "/Applicability_1725803037/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [ + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2018-16487", + "message": { + "text": "Prototype pollution `Object.freeze` remediation was detected" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 4, + "startColumn": 1, + "endLine": 4, + "endColumn": 32, + "snippet": { + "text": "Object.freeze(Object.prototype)" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2018-16487", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + } + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2019-10744", + "message": { + "text": "Prototype pollution `Object.freeze` remediation was detected" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 4, + "startColumn": 1, + "endLine": 4, + "endColumn": 32, + "snippet": { + "text": "Object.freeze(Object.prototype)" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2019-10744", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present." + } + }, + { + "ruleId": "applic_CVE-2020-28500", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." + } + }, + { + "ruleId": "applic_CVE-2020-8203", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." + } + }, + { + "ruleId": "applic_CVE-2021-23337", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." + } + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2022-29078", + "message": { + "text": "Prototype pollution `Object.freeze` remediation was detected" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 4, + "startColumn": 1, + "endLine": 4, + "endColumn": 32, + "snippet": { + "text": "Object.freeze(Object.prototype)" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2022-29078", + "kind": "pass", + "message": { + "text": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present." + } + }, + { + "ruleId": "applic_CVE-2024-33883", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `ejs.compile()` is called." + } + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2023-29827", + "message": { + "text": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 14, + "startColumn": 1, + "endLine": 14, + "endColumn": 30, + "snippet": { + "text": "app.set('view engine', 'ejs')" + } + } + } + } + ] + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2023-29827", + "message": { + "text": "The vulnerable function render is called" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 26, + "startColumn": 3, + "endLine": 26, + "endColumn": 38, + "snippet": { + "text": "res.render('pages/index',req.query)" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2024-39249", + "kind": "pass", + "message": { + "text": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + } + } + ] + } + ], + "secrets": [ + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Secrets scanner", + "rules": [ + { + "id": "REQ.SECRET.GENERIC.TEXT", + "name": "REQ.SECRET.GENERIC.TEXT", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.TEXT" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.GENERIC.CODE", + "name": "REQ.SECRET.GENERIC.CODE", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.CODE" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.KEYS", + "name": "REQ.SECRET.KEYS", + "shortDescription": { + "text": "Scanner for REQ.SECRET.KEYS" + }, + "fullDescription": { + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + }, + { + "id": "REQ.CRED.PUBLIC-ONLY", + "name": "REQ.CRED.PUBLIC-ONLY", + "shortDescription": { + "text": "Scanner for REQ.CRED.PUBLIC-ONLY" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "undetermined", + "conclusion": "private" + } + }, + { + "id": "REQ.SECRET.GENERIC.URL-TEXT", + "name": "REQ.SECRET.GENERIC.URL-TEXT", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.URL-TEXT" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "analyzerManager/jas_scanner/jas_scanner", + "scan", + "/Secrets_1725803029/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [ + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + }, + "region": { + "startLine": 2, + "startColumn": 1, + "endLine": 2, + "endColumn": 11, + "snippet": { + "text": "Sqc************" + } + } + } + } + ] + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + }, + "region": { + "startLine": 3, + "startColumn": 1, + "endLine": 3, + "endColumn": 11, + "snippet": { + "text": "gho************" + } + } + } + } + ] + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 11, + "startColumn": 14, + "endLine": 11, + "endColumn": 24, + "snippet": { + "text": "Sqc************" + } + } + } + } + ] + } + ] + } + ], + "iac": [ + { + "tool": { + "driver": { + "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/infrastructure-as-code-iac", + "name": "JFrog Terraform scanner", + "rules": [], + "version": "1.8.14" + } + }, + "invocations": [ + { + "arguments": [ + "analyzerManager/iac_scanner/tf_scanner", + "scan", + "/IaC_1725803037/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [] + } + ], + "sast": [ + { + "tool": { + "driver": { + "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sast", + "name": "USAF", + "rules": [ + { + "id": "js-express-without-helmet", + "shortDescription": { + "text": "Express Not Using Helmet" + }, + "fullDescription": { + "text": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n", + "markdown": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n" + }, + "defaultConfiguration": { + "parameters": { + "properties": { + "CWE": "693" + } + } + }, + "properties": { + "security-severity": "3.9" + } + }, + { + "id": "js-insecure-random", + "shortDescription": { + "text": "Use of Insecure Random" + }, + "fullDescription": { + "text": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n", + "markdown": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" + }, + "defaultConfiguration": { + "parameters": { + "properties": { + "CWE": "338" + } + } + }, + "properties": { + "security-severity": "3.9" + } + }, + { + "id": "js-template-injection", + "shortDescription": { + "text": "Template Object Injection" + }, + "fullDescription": { + "text": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n", + "markdown": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n" + }, + "defaultConfiguration": { + "parameters": { + "properties": { + "CWE": "73" + } + } + }, + "properties": { + "security-severity": "8.9" + } + } + ], + "version": "1.8.14" + } + }, + "invocations": [ + { + "arguments": [ + "analyzerManager/zd_scanner/scanner", + "scan", + "/Sast_1725803040/results.sarif", + "/Sast_1725803040/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/Users/user/ejs-frog-demo" + } + } + ], + "results": [ + { + "ruleId": "js-template-injection", + "level": "error", + "message": { + "text": "Template Object Injection" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 26, + "startColumn": 28, + "endLine": 26, + "endColumn": 37, + "snippet": { + "text": "req.query" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + ], + "fingerprints": { + "precise_sink_and_sink_function": "a549106dc43cdc0d36b0f81d0465a5d2" + }, + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 21, + "startColumn": 23, + "endLine": 21, + "endColumn": 26, + "snippet": { + "text": "req" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 26, + "startColumn": 28, + "endLine": 26, + "endColumn": 31, + "snippet": { + "text": "req" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 26, + "startColumn": 28, + "endLine": 26, + "endColumn": 37, + "snippet": { + "text": "req.query" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server.^_4" + } + ] + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "js-insecure-random", + "level": "note", + "message": { + "text": "Use of Insecure Random" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" + }, + "region": { + "startLine": 136, + "startColumn": 22, + "endLine": 136, + "endColumn": 35, + "snippet": { + "text": "Math.random()" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "public.js.bootstrap.^_0.Util.getUID" + } + ] + } + ], + "fingerprints": { + "precise_sink_and_sink_function": "34331455b0d5edf4c232dd288225780e" + } + }, + { + "ruleId": "js-insecure-random", + "level": "note", + "message": { + "text": "Use of Insecure Random" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + }, + "region": { + "startLine": 135, + "startColumn": 22, + "endLine": 135, + "endColumn": 35, + "snippet": { + "text": "Math.random()" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "public.js.bootstrap\u003cdot\u003ebundle.^_0.Util.getUID" + } + ] + } + ], + "fingerprints": { + "precise_sink_and_sink_function": "281a027677521fa64de4ce1fe14e01ab" + } + }, + { + "ruleId": "js-express-without-helmet", + "level": "note", + "message": { + "text": "Express Not Using Helmet" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///Users/user/ejs-frog-demo/server.js" + }, + "region": { + "startLine": 8, + "startColumn": 11, + "endLine": 8, + "endColumn": 20, + "snippet": { + "text": "express()" + } + } + }, + "logicalLocations": [ + { + "fullyQualifiedName": "server" + } + ] + } + ], + "fingerprints": { + "precise_sink_and_sink_function": "f8caf6a43a2c1eb41369843ca3c7d94c" + } + } + ] + } + ] + } + } + ] +} \ No newline at end of file diff --git a/tests/testdata/other/output/formats/audit_sarif.json b/tests/testdata/output/audit/audit_sarif.json similarity index 59% rename from tests/testdata/other/output/formats/audit_sarif.json rename to tests/testdata/output/audit/audit_sarif.json index d37a0f55..107ecbdf 100644 --- a/tests/testdata/other/output/formats/audit_sarif.json +++ b/tests/testdata/output/audit/audit_sarif.json @@ -10,7 +10,6 @@ "rules": [ { "id": "REQ.SECRET.GENERIC.TEXT", - "name": "REQ.SECRET.GENERIC.TEXT", "shortDescription": { "text": "Scanner for REQ.SECRET.GENERIC.TEXT" }, @@ -18,6 +17,10 @@ "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" }, + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, "properties": { "applicability": "not_applicable", "conclusion": "positive" @@ -25,7 +28,6 @@ }, { "id": "REQ.SECRET.GENERIC.CODE", - "name": "REQ.SECRET.GENERIC.CODE", "shortDescription": { "text": "Scanner for REQ.SECRET.GENERIC.CODE" }, @@ -33,40 +35,68 @@ "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" }, + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, "properties": { "applicability": "not_applicable", "conclusion": "positive" } }, { - "id": "REQ.SECRET.GENERIC.URL", - "name": "REQ.SECRET.GENERIC.URL", + "id": "REQ.SECRET.KEYS", "shortDescription": { - "text": "Scanner for REQ.SECRET.GENERIC.URL" + "text": "Scanner for REQ.SECRET.KEYS" }, "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + "help": { + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" }, "properties": { - "applicability": "not_applicable", - "conclusion": "positive" + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" } }, { - "id": "REQ.SECRET.KEYS", - "name": "REQ.SECRET.KEYS", + "id": "REQ.CRED.PUBLIC-ONLY", "shortDescription": { - "text": "Scanner for REQ.SECRET.KEYS" + "text": "Scanner for REQ.CRED.PUBLIC-ONLY" }, "fullDescription": { - "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", - "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + "text": "", + "markdown": "" + }, + "help": { + "text": "", + "markdown": "" }, "properties": { - "applicability": "applicable", - "conclusion": "negative", - "security-severity": 6.9 + "applicability": "undetermined", + "conclusion": "private" + } + }, + { + "id": "REQ.SECRET.GENERIC.URL-TEXT", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.URL-TEXT" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" } } ], @@ -78,7 +108,7 @@ "arguments": [ "analyzerManager/jas_scanner/jas_scanner", "scan", - "Secrets/config.yaml" + "/Secrets_1725867313/config.yaml" ], "executionSuccessful": true, "workingDirectory": { @@ -88,30 +118,10 @@ ], "results": [ { - "ruleId": "REQ.SECRET.KEYS", - "message": { - "text": "Secret keys were found" + "properties": { + "metadata": "", + "tokenValidation": "" }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" - }, - "region": { - "startLine": 1, - "startColumn": 0, - "endLine": 1, - "endColumn": 0, - "snippet": { - "text": "AKI************" - } - } - } - } - ] - }, - { "ruleId": "REQ.SECRET.KEYS", "message": { "text": "Secret keys were found" @@ -120,13 +130,13 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + "uri": "fake-creds.txt" }, "region": { "startLine": 2, - "startColumn": 0, + "startColumn": 1, "endLine": 2, - "endColumn": 0, + "endColumn": 11, "snippet": { "text": "Sqc************" } @@ -136,6 +146,10 @@ ] }, { + "properties": { + "metadata": "", + "tokenValidation": "" + }, "ruleId": "REQ.SECRET.KEYS", "message": { "text": "Secret keys were found" @@ -144,13 +158,13 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/fake-creds.txt" + "uri": "fake-creds.txt" }, "region": { "startLine": 3, - "startColumn": 0, + "startColumn": 1, "endLine": 3, - "endColumn": 0, + "endColumn": 11, "snippet": { "text": "gho************" } @@ -160,30 +174,10 @@ ] }, { - "ruleId": "REQ.SECRET.KEYS", - "message": { - "text": "Secret keys were found" + "properties": { + "metadata": "", + "tokenValidation": "" }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" - }, - "region": { - "startLine": 10, - "startColumn": 15, - "endLine": 10, - "endColumn": 15, - "snippet": { - "text": "AKI************" - } - } - } - } - ] - }, - { "ruleId": "REQ.SECRET.KEYS", "message": { "text": "Secret keys were found" @@ -192,15 +186,15 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "server.js" }, "region": { "startLine": 11, - "startColumn": 12, + "startColumn": 14, "endLine": 11, - "endColumn": 12, + "endColumn": 24, "snippet": { - "text": "\"Sq************" + "text": "Sqc************" } } } @@ -215,7 +209,7 @@ "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/infrastructure-as-code-iac", "name": "JFrog Terraform scanner", "rules": [], - "version": "1.8.3" + "version": "1.8.14" } }, "invocations": [ @@ -223,7 +217,7 @@ "arguments": [ "analyzerManager/iac_scanner/tf_scanner", "scan", - "/IaC/config.yaml" + "/IaC_1725867328/config.yaml" ], "executionSuccessful": true, "workingDirectory": { @@ -248,8 +242,19 @@ "text": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n", "markdown": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n" }, + "defaultConfiguration": { + "parameters": { + "properties": { + "CWE": "693" + } + } + }, + "help": { + "text": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n", + "markdown": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n" + }, "properties": { - "security-severity": 3.9 + "security-severity": "3.9" } }, { @@ -268,8 +273,12 @@ } } }, + "help": { + "text": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n", + "markdown": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" + }, "properties": { - "security-severity": 3.9 + "security-severity": "3.9" } }, { @@ -288,12 +297,16 @@ } } }, + "help": { + "text": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n", + "markdown": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n" + }, "properties": { - "security-severity": 8.9 + "security-severity": "8.9" } } ], - "version": "1.8.3" + "version": "1.8.14" } }, "invocations": [ @@ -301,8 +314,8 @@ "arguments": [ "analyzerManager/zd_scanner/scanner", "scan", - "Sast/results.sarif", - "Sast/config.yaml" + "/Sast_1725867332/results.sarif", + "/Sast_1725867332/config.yaml" ], "executionSuccessful": true, "workingDirectory": { @@ -321,7 +334,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.js" + "uri": "public/js/bootstrap.js" }, "region": { "startLine": 136, @@ -339,7 +352,10 @@ } ] } - ] + ], + "fingerprints": { + "precise_sink_and_sink_function": "3cb8327f723c9d1b6664949748868899" + } }, { "ruleId": "js-insecure-random", @@ -351,7 +367,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/public/js/bootstrap.bundle.js" + "uri": "public/js/bootstrap.bundle.js" }, "region": { "startLine": 135, @@ -365,11 +381,14 @@ }, "logicalLocations": [ { - "fullyQualifiedName": "public.js.bootstrap\u003cdot\u003ebundle.^_0.Util.getUID" + "fullyQualifiedName": "public.js.bootstrapbundle.^_0.Util.getUID" } ] } - ] + ], + "fingerprints": { + "precise_sink_and_sink_function": "ec68d229b6bdd85b67dd2ddce27337bd" + } }, { "ruleId": "js-express-without-helmet", @@ -381,7 +400,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "server.js" }, "region": { "startLine": 8, @@ -399,7 +418,10 @@ } ] } - ] + ], + "fingerprints": { + "precise_sink_and_sink_function": "f8caf6a43a2c1eb41369843ca3c7d94c" + } }, { "ruleId": "js-template-injection", @@ -411,7 +433,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "server.js" }, "region": { "startLine": 26, @@ -430,6 +452,9 @@ ] } ], + "fingerprints": { + "precise_sink_and_sink_function": "a549106dc43cdc0d36b0f81d0465a5d2" + }, "codeFlows": [ { "threadFlows": [ @@ -439,7 +464,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "server.js" }, "region": { "startLine": 21, @@ -462,7 +487,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "server.js" }, "region": { "startLine": 26, @@ -485,7 +510,7 @@ "location": { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/server.js" + "uri": "server.js" }, "region": { "startLine": 26, @@ -516,7 +541,7 @@ "tool": { "driver": { "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sca", - "name": "JFrog Xray SCA", + "name": "JFrog Xray Scanner", "rules": [ { "id": "CVE-2018-3721_lodash_4.17.0", @@ -545,94 +570,94 @@ } }, { - "id": "CVE-2018-16487_lodash_4.17.0", + "id": "CVE-2019-1010266_lodash_4.17.0", "shortDescription": { - "text": "[CVE-2018-16487] lodash 4.17.0" + "text": "[CVE-2019-1010266] lodash 4.17.0" }, "help": { - "text": "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.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.6 | Not Applicable | `lodash 4.17.0` | [4.17.11] |" + "text": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.11] |" }, "properties": { - "security-severity": "5.6" + "security-severity": "6.5" } }, { - "id": "CVE-2024-39249_async_3.2.4", + "id": "CVE-2024-33883_ejs_3.1.6", "shortDescription": { - "text": "[CVE-2024-39249] async 3.2.4" + "text": "[CVE-2024-33883] ejs 3.1.6" }, "help": { - "text": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Not Covered | `ejs 3.1.6` | No fix available |" + "text": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 4.0 | Not Applicable | `ejs 3.1.6` | [3.1.10] |" }, "properties": { - "security-severity": "0.0" + "security-severity": "4.0" } }, { - "id": "CVE-2024-29041_express_4.18.2", + "id": "CVE-2023-29827_ejs_3.1.6", "shortDescription": { - "text": "[CVE-2024-29041] express 4.18.2" + "text": "[CVE-2023-29827] ejs 3.1.6" }, "help": { - "text": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.1 | Not Covered | `express 4.18.2` | [4.19.2], [5.0.0-beta.3] |" + "text": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Applicable | `ejs 3.1.6` | No fix available |" }, "properties": { - "security-severity": "6.1" + "security-severity": "9.8" } }, { - "id": "CVE-2024-33883_ejs_3.1.6", + "id": "CVE-2024-39249_async_3.2.4", "shortDescription": { - "text": "[CVE-2024-33883] ejs 3.1.6" + "text": "[CVE-2024-39249] async 3.2.4" }, "help": { - "text": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.9 | Not Applicable | `ejs 3.1.6` | [3.1.10] |" + "text": "Async <= 2.6.4 and <= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Not Covered | `ejs 3.1.6` | No fix available |" }, "properties": { - "security-severity": "6.9" + "security-severity": "0.0" } }, { - "id": "CVE-2020-8203_lodash_4.17.0", + "id": "CVE-2020-28500_lodash_4.17.0", "shortDescription": { - "text": "[CVE-2020-8203] lodash 4.17.0" + "text": "[CVE-2020-28500] lodash 4.17.0" }, "help": { - "text": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.4 | Not Applicable | `lodash 4.17.0` | [4.17.19] |" + "text": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.3 | Not Applicable | `lodash 4.17.0` | [4.17.21] |" }, "properties": { - "security-severity": "7.4" + "security-severity": "5.3" } }, { - "id": "CVE-2020-28500_lodash_4.17.0", + "id": "CVE-2020-8203_lodash_4.17.0", "shortDescription": { - "text": "[CVE-2020-28500] lodash 4.17.0" + "text": "[CVE-2020-8203] lodash 4.17.0" }, "help": { - "text": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.3 | Not Applicable | `lodash 4.17.0` | [4.17.21] |" + "text": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.4 | Not Applicable | `lodash 4.17.0` | [4.17.19] |" }, "properties": { - "security-severity": "5.3" + "security-severity": "7.4" } }, { - "id": "CVE-2023-29827_ejs_3.1.6", + "id": "CVE-2019-10744_lodash_4.17.0", "shortDescription": { - "text": "[CVE-2023-29827] ejs 3.1.6" + "text": "[CVE-2019-10744] lodash 4.17.0" }, "help": { - "text": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Applicable | `ejs 3.1.6` | No fix available |" + "text": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.1 | Not Applicable | `lodash 4.17.0` | [4.17.12] |" }, "properties": { - "security-severity": "9.8" + "security-severity": "9.1" } }, { @@ -649,33 +674,33 @@ } }, { - "id": "CVE-2019-10744_lodash_4.17.0", + "id": "CVE-2024-29041_express_4.18.2", "shortDescription": { - "text": "[CVE-2019-10744] lodash 4.17.0" + "text": "[CVE-2024-29041] express 4.18.2" }, "help": { - "text": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.1 | Not Applicable | `lodash 4.17.0` | [4.17.12] |" + "text": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.1 | Not Covered | `express 4.18.2` | [4.19.2], [5.0.0-beta.3] |" }, "properties": { - "security-severity": "9.1" + "security-severity": "6.1" } }, { - "id": "CVE-2019-1010266_lodash_4.17.0", + "id": "CVE-2018-16487_lodash_4.17.0", "shortDescription": { - "text": "[CVE-2019-1010266] lodash 4.17.0" + "text": "[CVE-2018-16487] lodash 4.17.0" }, "help": { - "text": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 6.5 | Not Covered | `lodash 4.17.0` | [4.17.11] |" + "text": "A prototype pollution vulnerability was found in lodash <4.17.11 where the functions merge, mergeWith, and defaultsDeep can be tricked into adding or modifying properties of Object.prototype.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 5.6 | Not Applicable | `lodash 4.17.0` | [4.17.11] |" }, "properties": { - "security-severity": "6.5" + "security-severity": "5.6" } } ], - "version": "3.98.2" + "version": "3.104.8" } }, "invocations": [ @@ -693,7 +718,7 @@ "fixedVersion": "[4.19.2], [5.0.0-beta.3]" }, "ruleId": "CVE-2024-29041_express_4.18.2", - "ruleIndex": 4, + "ruleIndex": 10, "level": "warning", "message": { "text": "[CVE-2024-29041] express 4.18.2" @@ -702,7 +727,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "package.json" } } } @@ -710,20 +735,20 @@ }, { "properties": { - "applicability": "Applicable", + "applicability": "Not Covered", "fixedVersion": "No fix available" }, - "ruleId": "CVE-2023-29827_ejs_3.1.6", - "ruleIndex": 8, - "level": "error", + "ruleId": "CVE-2024-39249_async_3.2.4", + "ruleIndex": 5, + "level": "none", "message": { - "text": "[CVE-2023-29827] ejs 3.1.6" + "text": "[CVE-2024-39249] ejs 3.1.6" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "package.json" } } } @@ -732,19 +757,61 @@ { "properties": { "applicability": "Not Applicable", - "fixedVersion": "[3.1.7]" + "fixedVersion": "[4.17.21]" }, - "ruleId": "CVE-2022-29078_ejs_3.1.6", - "ruleIndex": 9, + "ruleId": "CVE-2020-28500_lodash_4.17.0", + "ruleIndex": 6, + "level": "warning", + "message": { + "text": "[CVE-2020-28500] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "package.json" + } + } + } + ] + }, + { + "properties": { + "applicability": "Not Covered", + "fixedVersion": "[4.17.5]" + }, + "ruleId": "CVE-2018-3721_lodash_4.17.0", + "ruleIndex": 0, + "level": "warning", + "message": { + "text": "[CVE-2018-3721] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "package.json" + } + } + } + ] + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "[4.17.21]" + }, + "ruleId": "CVE-2021-23337_lodash_4.17.0", + "ruleIndex": 1, "level": "error", "message": { - "text": "[CVE-2022-29078] ejs 3.1.6" + "text": "[CVE-2021-23337] lodash 4.17.0" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "package.json" } } } @@ -753,19 +820,19 @@ { "properties": { "applicability": "Not Applicable", - "fixedVersion": "[3.1.10]" + "fixedVersion": "[4.17.11]" }, - "ruleId": "CVE-2024-33883_ejs_3.1.6", - "ruleIndex": 5, + "ruleId": "CVE-2018-16487_lodash_4.17.0", + "ruleIndex": 11, "level": "warning", "message": { - "text": "[CVE-2024-33883] ejs 3.1.6" + "text": "[CVE-2018-16487] lodash 4.17.0" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "package.json" } } } @@ -777,7 +844,7 @@ "fixedVersion": "[4.17.19]" }, "ruleId": "CVE-2020-8203_lodash_4.17.0", - "ruleIndex": 6, + "ruleIndex": 7, "level": "error", "message": { "text": "[CVE-2020-8203] lodash 4.17.0" @@ -786,7 +853,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "package.json" } } } @@ -798,7 +865,7 @@ "fixedVersion": "[4.17.12]" }, "ruleId": "CVE-2019-10744_lodash_4.17.0", - "ruleIndex": 10, + "ruleIndex": 8, "level": "error", "message": { "text": "[CVE-2019-10744] lodash 4.17.0" @@ -807,7 +874,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "package.json" } } } @@ -819,8 +886,137 @@ "fixedVersion": "[4.17.11]" }, "ruleId": "CVE-2019-1010266_lodash_4.17.0", + "ruleIndex": 2, + "level": "warning", + "message": { + "text": "[CVE-2019-1010266] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "package.json" + } + } + } + ] + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "[3.1.7]" + }, + "ruleId": "CVE-2022-29078_ejs_3.1.6", + "ruleIndex": 9, + "level": "error", + "message": { + "text": "[CVE-2022-29078] ejs 3.1.6" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "package.json" + } + } + } + ] + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "[3.1.10]" + }, + "ruleId": "CVE-2024-33883_ejs_3.1.6", + "ruleIndex": 3, + "level": "warning", + "message": { + "text": "[CVE-2024-33883] ejs 3.1.6" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "package.json" + } + } + } + ] + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2023-29827_ejs_3.1.6", + "ruleIndex": 4, + "level": "error", + "message": { + "text": "[CVE-2023-29827] ejs 3.1.6" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "package.json" + } + } + } + ] + }, + { + "properties": { + "applicability": "Not Covered", + "fixedVersion": "[4.19.2], [5.0.0-beta.3]", + "watch": "Security_watch_1" + }, + "ruleId": "CVE-2024-29041_express_4.18.2", + "ruleIndex": 10, + "level": "warning", + "message": { + "text": "[CVE-2024-29041] express 4.18.2" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "package.json" + } + } + } + ] + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "[4.17.11]", + "watch": "Security_watch_1" + }, + "ruleId": "CVE-2018-16487_lodash_4.17.0", "ruleIndex": 11, "level": "warning", + "message": { + "text": "[CVE-2018-16487] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "package.json" + } + } + } + ] + }, + { + "properties": { + "applicability": "Not Covered", + "fixedVersion": "[4.17.11]", + "watch": "Security_watch_1" + }, + "ruleId": "CVE-2019-1010266_lodash_4.17.0", + "ruleIndex": 2, + "level": "warning", "message": { "text": "[CVE-2019-1010266] lodash 4.17.0" }, @@ -828,7 +1024,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "package.json" } } } @@ -837,10 +1033,77 @@ { "properties": { "applicability": "Not Applicable", - "fixedVersion": "[4.17.21]" + "fixedVersion": "[3.1.10]", + "watch": "Security_watch_1" + }, + "ruleId": "CVE-2024-33883_ejs_3.1.6", + "ruleIndex": 3, + "level": "warning", + "message": { + "text": "[CVE-2024-33883] ejs 3.1.6" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "package.json" + } + } + } + ] + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "No fix available", + "watch": "Security_watch_1" + }, + "ruleId": "CVE-2023-29827_ejs_3.1.6", + "ruleIndex": 4, + "level": "error", + "message": { + "text": "[CVE-2023-29827] ejs 3.1.6" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "package.json" + } + } + } + ] + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "[4.17.12]", + "watch": "Security_watch_1" + }, + "ruleId": "CVE-2019-10744_lodash_4.17.0", + "ruleIndex": 8, + "level": "error", + "message": { + "text": "[CVE-2019-10744] lodash 4.17.0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "package.json" + } + } + } + ] + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "[4.17.21]", + "watch": "Security_watch_1" }, "ruleId": "CVE-2020-28500_lodash_4.17.0", - "ruleIndex": 7, + "ruleIndex": 6, "level": "warning", "message": { "text": "[CVE-2020-28500] lodash 4.17.0" @@ -849,7 +1112,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "package.json" } } } @@ -858,7 +1121,8 @@ { "properties": { "applicability": "Not Covered", - "fixedVersion": "[4.17.5]" + "fixedVersion": "[4.17.5]", + "watch": "Security_watch_1" }, "ruleId": "CVE-2018-3721_lodash_4.17.0", "ruleIndex": 0, @@ -870,7 +1134,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "package.json" } } } @@ -879,7 +1143,8 @@ { "properties": { "applicability": "Not Applicable", - "fixedVersion": "[4.17.21]" + "fixedVersion": "[4.17.21]", + "watch": "Security_watch_1" }, "ruleId": "CVE-2021-23337_lodash_4.17.0", "ruleIndex": 1, @@ -891,7 +1156,7 @@ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "package.json" } } } @@ -900,19 +1165,20 @@ { "properties": { "applicability": "Not Applicable", - "fixedVersion": "[4.17.11]" + "fixedVersion": "[4.17.19]", + "watch": "Security_watch_1" }, - "ruleId": "CVE-2018-16487_lodash_4.17.0", - "ruleIndex": 2, - "level": "warning", + "ruleId": "CVE-2020-8203_lodash_4.17.0", + "ruleIndex": 7, + "level": "error", "message": { - "text": "[CVE-2018-16487] lodash 4.17.0" + "text": "[CVE-2020-8203] lodash 4.17.0" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "package.json" } } } @@ -920,20 +1186,21 @@ }, { "properties": { - "applicability": "Not Covered", - "fixedVersion": "No fix available" + "applicability": "Not Applicable", + "fixedVersion": "[3.1.7]", + "watch": "Security_watch_1" }, - "ruleId": "CVE-2024-39249_async_3.2.4", - "ruleIndex": 3, - "level": "none", + "ruleId": "CVE-2022-29078_ejs_3.1.6", + "ruleIndex": 9, + "level": "error", "message": { - "text": "[CVE-2024-39249] ejs 3.1.6" + "text": "[CVE-2022-29078] ejs 3.1.6" }, "locations": [ { "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/user/ejs-frog-demo/package.json" + "uri": "package.json" } } } diff --git a/tests/testdata/output/audit/audit_simple_json.json b/tests/testdata/output/audit/audit_simple_json.json new file mode 100644 index 00000000..e710dc91 --- /dev/null +++ b/tests/testdata/output/audit/audit_simple_json.json @@ -0,0 +1,1862 @@ +{ + "multiScanId": "7d5e4733-3f93-11ef-8147-e610d09d7daa", + "vulnerabilities": [ + { + "severity": "Critical", + "impactedPackageName": "ejs", + "impactedPackageVersion": "3.1.6", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", + "applicable": "Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2023-29827", + "cvssV2": "", + "cvssV3": "9.8", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`", + "evidence": [ + { + "file": "server.js", + "startLine": 14, + "startColumn": 1, + "endLine": 14, + "endColumn": 30, + "snippet": "app.set('view engine', 'ejs')", + "reason": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" + } + ] + } + } + ], + "issueId": "XRAY-520200", + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2023-29827", + "https://github.com/mde/ejs/issues/720", + "https://github.com/mde/ejs/blob/main/SECURITY.md#out-of-scope-vulnerabilities" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "ejs", + "version": "3.1.6" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Low", + "summary": "Insufficient input validation can lead to template injection in ejs when attackers can control both the rendered template and rendering options.", + "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to bypass ejs' template injection restrictions, by abusing the `closeDelimiter` rendering option, in the case when -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\n\nThe vulnerability was **rightfully disputed** due to the fact that a vulnerable configuration is extremely unlikely to exist in any real-world setup. As such, the maintainers will not provide a fix for this (non-)issue.\n\nExample of a vulnerable application -\n```js\nconst express = require('express')\nconst app = express()\nconst port = 3000\n\napp.set('view engine', 'ejs');\n\napp.get('/page', (req,res) =\u003e {\n res.render('page', req.query); // OPTS (2nd parameter) IS ATTACKER-CONTROLLED\n})\n\napp.listen(port, () =\u003e {\n console.log(\"Example app listening on port ${port}\")\n})\n```\n\nContents of `page.ejs` (very unlikely to be attacker controlled) -\n```js\n%%1\");process.mainModule.require('child_process').execSync('calc');//\n```\n\nIn this case, sending `closeDelimiter` with the same malicious code that already exists at `page.ejs` will trigger the injection -\n`http://127.0.0.1:3000/page?settings[view%20options][closeDelimiter]=1\")%3bprocess.mainModule.require('child_process').execSync('calc')%3b//`", + "severityReasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS does not take into account the rarity of a vulnerable configuration to exist", + "isPositive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The vulnerability can be exploited only under the following conditions -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\nThis vulnerable configuration is extremely unlikely to exist in any real-world setup.", + "isPositive": true + }, + { + "name": "The issue has been disputed by the vendor", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "Published exploit demonstrates template injection" + } + ] + } + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", + "applicable": "Not Covered", + "fixedVersions": [ + "[4.17.11]" + ], + "cves": [ + { + "id": "CVE-2019-1010266", + "cvssV2": "4.0", + "cvssV3": "6.5", + "applicability": { + "status": "Not Covered" + } + } + ], + "issueId": "XRAY-85049", + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2019-1010266", + "https://github.com/lodash/lodash/wiki/Changelog", + "https://snyk.io/vuln/SNYK-JS-LODASH-73639", + "https://security.netapp.com/advisory/ntap-20190919-0004", + "https://security.netapp.com/advisory/ntap-20190919-0004/", + "https://github.com/lodash/lodash/issues/3359", + "https://github.com/lodash/lodash/commit/5c08f18d365b64063bfbfa686cbb97cdd6267347" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", + "applicable": "Not Covered", + "fixedVersions": [ + "[4.17.5]" + ], + "cves": [ + { + "id": "CVE-2018-3721", + "cvssV2": "4.0", + "cvssV3": "6.5", + "applicability": { + "status": "Not Covered" + } + } + ], + "issueId": "XRAY-72918", + "references": [ + "https://www.npmjs.com/advisories/577", + "https://hackerone.com/reports/310443", + "https://github.com/advisories/GHSA-fvqr-27wr-82fm", + "https://nvd.nist.gov/vuln/detail/CVE-2018-3721", + "https://security.netapp.com/advisory/ntap-20190919-0004", + "https://security.netapp.com/advisory/ntap-20190919-0004/", + "https://github.com/lodash/lodash/commit/d8e069cc3410082e44eb18fcf8e7f3d08ebe1d4a" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Medium", + "impactedPackageName": "express", + "impactedPackageVersion": "4.18.2", + "impactedPackageType": "npm", + "components": [ + { + "name": "express", + "version": "4.18.2", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", + "applicable": "Not Covered", + "fixedVersions": [ + "[4.19.2]", + "[5.0.0-beta.3]" + ], + "cves": [ + { + "id": "CVE-2024-29041", + "cvssV2": "", + "cvssV3": "6.1", + "applicability": { + "status": "Not Covered" + } + } + ], + "issueId": "XRAY-594935", + "references": [ + "https://github.com/koajs/koa/issues/1800", + "https://github.com/expressjs/express/pull/5539", + "https://github.com/expressjs/express/commit/0b746953c4bd8e377123527db11f9cd866e39f94", + "https://github.com/expressjs/express/commit/0867302ddbde0e9463d0564fea5861feb708c2dd", + "https://github.com/advisories/GHSA-rv95-896h-c2vc", + "https://expressjs.com/en/4x/api.html#res.location", + "https://nvd.nist.gov/vuln/detail/CVE-2024-29041", + "https://github.com/expressjs/express/security/advisories/GHSA-rv95-896h-c2vc" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "express", + "version": "4.18.2" + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Unknown", + "impactedPackageName": "async", + "impactedPackageVersion": "3.2.4", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "Async \u003c= 2.6.4 and \u003c= 3.2.5 are vulnerable to ReDoS (Regular Expression Denial of Service) while parsing function in autoinject function. NOTE: this is disputed by the supplier because there is no realistic threat model: regular expressions are not used with untrusted input.", + "applicable": "Not Covered", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-39249", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Not Covered", + "scannerDescription": "Never applicable. The vulnerability is exploitable only if an attacker has access to the source code." + } + } + ], + "issueId": "XRAY-609848", + "references": [ + "https://github.com/zunak/CVE-2024-39249", + "https://github.com/caolan/async/blob/v3.2.5/lib/autoInject.js#L41", + "https://nvd.nist.gov/vuln/detail/CVE-2024-39249", + "https://github.com/caolan/async/blob/v3.2.5/lib/autoInject.js#L6", + "https://github.com/caolan/async/issues/1975#issuecomment-2204528153", + "https://github.com/zunak/CVE-2024-39249/issues/1" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "ejs", + "version": "3.1.6" + }, + { + "name": "jake", + "version": "10.8.7" + }, + { + "name": "async", + "version": "3.2.4" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Low", + "summary": "ReDoS in Async may lead to denial of service while parsing malformed source code.", + "severityReasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The reported CVSS does not reflect the severity of the vulnerability.", + "isPositive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "To exploit this issue an attacker must change the source code of the application. In cases where an attacker can already modify (or fully control) the source code, the attacker can immediately achieve arbitrary code execution - thus this issue has almost no security impact.", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "A proof-of-concept has been published in the advisory." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The issue requires the use of the `async.autoInject` function to be vulnerable.", + "isPositive": true + } + ] + } + }, + { + "severity": "Critical", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.12]" + ], + "cves": [ + { + "id": "CVE-2019-10744", + "cvssV2": "6.4", + "cvssV3": "9.1", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present.", + "evidence": [ + { + "file": "server.js", + "startLine": 4, + "startColumn": 1, + "endLine": 4, + "endColumn": 32, + "snippet": "Object.freeze(Object.prototype)", + "reason": "Prototype pollution `Object.freeze` remediation was detected" + } + ] + } + } + ], + "issueId": "XRAY-85679", + "references": [ + "https://www.npmjs.com/advisories/1065", + "https://github.com/lodash/lodash/pull/4336", + "https://www.oracle.com/security-alerts/cpujan2021.html", + "https://security.netapp.com/advisory/ntap-20191004-0005/", + "https://snyk.io/vuln/SNYK-JS-LODASH-450202", + "https://support.f5.com/csp/article/K47105354?utm_source=f5support\u0026amp;utm_medium=RSS", + "https://access.redhat.com/errata/RHSA-2019:3024", + "https://www.oracle.com/security-alerts/cpuoct2020.html", + "https://support.f5.com/csp/article/K47105354?utm_source=f5support\u0026amp%3Butm_medium=RSS", + "https://github.com/advisories/GHSA-jf85-cpcp-j695", + "https://nvd.nist.gov/vuln/detail/CVE-2019-10744" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "High", + "summary": "Insufficient input validation in lodash defaultsDeep() leads to prototype pollution.", + "details": "[lodash](https://www.npmjs.com/package/lodash) is a modern JavaScript utility library delivering modularity, performance, \u0026 extras.\n\nThe function `defaultsDeep` was found to be vulnerable to prototype pollution, when accepting arbitrary source objects from untrusted input\n\nExample of code vulnerable to this issue - \n```js\nconst lodash = require('lodash'); \nconst evilsrc = {constructor: {prototype: {evilkey: \"evilvalue\"}}};\nlodash.defaultsDeep({}, evilsrc)\n```", + "severityReasons": [ + { + "name": "The issue has an exploit published", + "description": "A public PoC demonstrates exploitation of this issue" + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", + "isPositive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find remote input that propagates into the `defaultsDeep` method (2nd arg)", + "isPositive": true + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." + } + }, + { + "severity": "Critical", + "impactedPackageName": "ejs", + "impactedPackageVersion": "3.1.6", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", + "applicable": "Not Applicable", + "fixedVersions": [ + "[3.1.7]" + ], + "cves": [ + { + "id": "CVE-2022-29078", + "cvssV2": "7.5", + "cvssV3": "9.8", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "evidence": [ + { + "file": "server.js", + "startLine": 4, + "startColumn": 1, + "endLine": 4, + "endColumn": 32, + "snippet": "Object.freeze(Object.prototype)", + "reason": "Prototype pollution `Object.freeze` remediation was detected" + } + ] + } + } + ], + "issueId": "XRAY-209002", + "references": [ + "https://github.com/mde/ejs/commit/15ee698583c98dadc456639d6245580d17a24baf", + "https://eslam.io/posts/ejs-server-side-template-injection-rce/", + "https://security.netapp.com/advisory/ntap-20220804-0001", + "https://github.com/mde/ejs/releases", + "https://nvd.nist.gov/vuln/detail/CVE-2022-29078", + "https://eslam.io/posts/ejs-server-side-template-injection-rce", + "https://github.com/mde/ejs", + "https://security.netapp.com/advisory/ntap-20220804-0001/" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "ejs", + "version": "3.1.6" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Insufficient input validation in EJS enables attackers to perform template injection when attacker can control the rendering options.", + "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to perform template injection on the `opts.outputFunctionName` variable, since the variable is injected into the template body without any escaping. Although it is unlikely that the attacker can directly control the `outputFunctionName` property, it is possible that it can be influenced in conjunction with a prototype pollution vulnerability.\n\nOnce template injection is achieved, the attacker can immediately perform remote code execution since the template engine (EJS) allows executing arbitrary JavaScript code.\n\nExample of a vulnerable Node.js application -\n```js\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst lodash = require('lodash');\nconst ejs = require('ejs');\n\nconst app = express();\n\napp\n .use(bodyParser.urlencoded({extended: true}))\n .use(bodyParser.json());\n\napp.set('views', './');\napp.set('view engine', 'ejs');\n\napp.get(\"/\", (req, res) =\u003e {\n res.render('index');\n});\n\napp.post(\"/\", (req, res) =\u003e {\n let data = {};\n let input = JSON.parse(req.body.content);\n lodash.defaultsDeep(data, input);\n res.json({message: \"OK\"});\n});\n\nlet server = app.listen(8086, '0.0.0.0', function() {\n console.log('Listening on port %d', server.address().port);\n});\n```\n\nExploiting the above example for RCE -\n`curl 127.0.0.1:8086 -v --data 'content={\"constructor\": {\"prototype\": {\"outputFunctionName\": \"a; return global.process.mainModule.constructor._load(\\\"child_process\\\").execSync(\\\"whoami\\\"); //\"}}}'\n`\n\nDue to the prototype pollution in the `lodash.defaultsDeep` call, an attacker can inject the `outputFunctionName` property with an arbitrary value. The chosen value executes an arbitrary process via the `child_process` module.", + "severityReasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker has to find a way to get their malicious input to `opts.outputFunctionName`, which will usually require exploitation of a prototype pollution vulnerability somewhere else in the code. However, there could be cases where the attacker can pass malicious data to the render function directly because of design problems in other code using EJS.", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "There are multiple examples of exploits for this vulnerability online." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Successful exploitation of this vulnerability leads to remote code execution." + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\nNote that this mitigation is supposed to stop any prototype pollution attacks which can allow an attacker to control the `opts.outputFunctionName` parameter indirectly.\n\nThe mitigation will not stop any (extremely unlikely) scenarios where the JavaScript code allows external input to directly affect `opts.outputFunctionName`." + } + }, + { + "severity": "High", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.21]" + ], + "cves": [ + { + "id": "CVE-2021-23337", + "cvssV2": "6.5", + "cvssV3": "7.2", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." + } + } + ], + "issueId": "XRAY-140575", + "references": [ + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1074929", + "https://security.netapp.com/advisory/ntap-20210312-0006/", + "https://snyk.io/vuln/SNYK-JS-LODASH-1040724", + "https://security.netapp.com/advisory/ntap-20210312-0006", + "https://www.oracle.com/security-alerts/cpujan2022.html", + "https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c", + "https://cert-portal.siemens.com/productcert/pdf/ssa-637483.pdf", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWER-1074928", + "https://www.oracle.com/security-alerts/cpuoct2021.html", + "https://snyk.io/vuln/SNYK-JAVA-ORGFUJIONWEBJARS-1074932", + "https://github.com/lodash/lodash/blob/ddfd9b11a0126db2302cb70ec9973b66baec0975/lodash.js%23L14851", + "https://github.com/advisories/GHSA-35jh-r3h4-6jhm", + "https://www.oracle.com/security-alerts/cpujul2022.html", + "https://www.oracle.com//security-alerts/cpujul2021.html", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARS-1074930", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWERGITHUBLODASH-1074931", + "https://nvd.nist.gov/vuln/detail/CVE-2021-23337", + "https://github.com/lodash/lodash/blob/ddfd9b11a0126db2302cb70ec9973b66baec0975/lodash.js#L14851" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Improper sanitization in the lodash template function leads to JavaScript code injection through the options argument.", + "details": "JavaScript-based applications (both frontend and backend) that use the [template function](https://lodash.com/docs/4.17.15#template) -`_.template([string=''], [options={}])` from the [lodash](https://lodash.com/) utility library and provide the `options` argument (specifically the `variable` option) from untrusted user input, are vulnerable to JavaScript code injection. This issue can be easily exploited, and an exploitation example is [publicly available](https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c#diff-a561630bb56b82342bc66697aee2ad96efddcbc9d150665abd6fb7ecb7c0ab2fR22303) in the fix tests that was introduced in version 4.17.21 - \n```js\nlodash.template('', { variable: '){console.log(process.env)}; with(obj' })()\n```", + "severityReasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "It is highly unlikely that a JS program will accept arbitrary remote input into the template's `options` argument", + "isPositive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must find remote input that propagates into the `options` argument of a `template` call", + "isPositive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Leads to remote code execution through JS code injection" + }, + { + "name": "The issue has an exploit published", + "description": "Published exploit demonstrates arbitrary JS code execution" + } + ] + } + }, + { + "severity": "High", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.19]" + ], + "cves": [ + { + "id": "CVE-2020-8203", + "cvssV2": "5.8", + "cvssV3": "7.4", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." + } + } + ], + "issueId": "XRAY-114089", + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2020-8203", + "https://www.oracle.com/security-alerts/cpuapr2022.html", + "https://hackerone.com/reports/864701", + "https://hackerone.com/reports/712065", + "https://github.com/advisories/GHSA-p6mc-m468-83gw", + "https://www.oracle.com//security-alerts/cpujul2021.html", + "https://github.com/lodash/lodash/issues/4744", + "https://www.oracle.com/security-alerts/cpuApr2021.html", + "https://github.com/github/advisory-database/pull/2884", + "https://www.oracle.com/security-alerts/cpujan2022.html", + "https://github.com/lodash/lodash/commit/c84fe82760fb2d3e03a63379b297a1cc1a2fce12", + "https://security.netapp.com/advisory/ntap-20200724-0006/", + "https://web.archive.org/web/20210914001339/https://github.com/lodash/lodash/issues/4744", + "https://www.oracle.com/security-alerts/cpuoct2021.html", + "https://github.com/lodash/lodash/issues/4874", + "https://github.com/lodash/lodash/wiki/Changelog#v41719" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Critical", + "summary": "Prototype pollution in lodash object merging and zipping functions leads to code injection.", + "details": "[lodash](https://lodash.com/) is a JavaScript library which provides utility functions for common programming tasks.\n\nJavaScript frontend and Node.js-based backend applications that merge or zip objects using the lodash functions `mergeWith`, `merge` and `zipObjectDeep` are vulnerable to [prototype pollution](https://medium.com/node-modules/what-is-prototype-pollution-and-why-is-it-such-a-big-deal-2dd8d89a93c) if one or more of the objects it receives as arguments are obtained from user input. \nAn attacker controlling this input given to the vulnerable functions can inject properties to JavaScript special objects such as [Object.prototype](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes) from which all JavaScript objects inherit properties and methods. Any change on `Object.prototype` properties will then propagate through the prototype chain inheritance to all of the objects in a JavaScript application. This in turn would allow an attacker to add new properties or modify existing properties which will have application specific implications that could lead to DoS (denial of service), authentication bypass, privilege escalation and even RCE (remote code execution) in [some cases](https://youtu.be/LUsiFV3dsK8?t=1152). \nAs an example for privilege escalation, consider a JavaScript application that has a `user` object which has a Boolean property of `user.isAdmin` which is used to decide which actions the user may take. If an attacker can modify or add the `isAdmin` property through prototype pollution, it can escalate the privileges of its own user to those of an admin. \nAs exploitation is usually application specific, successful exploitation is much more likely if an attacker have access to the JavaScript application code. As such, frontend applications are more vulnerable to this vulnerability than Node.js backend applications.", + "severityReasons": [ + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "isPositive": true + }, + { + "name": "The issue can be exploited by attackers over the network" + }, + { + "name": "The issue is trivial to exploit and does not require a published writeup or PoC" + } + ], + "remediation": "##### Deployment mitigations\n\nAs general guidelines against prototype pollution, first consider not merging objects originating from user input or using a Map structure instead of an object. If merging objects is needed, look into creating objects without a prototype with `Object.create(null)` or into freezing `Object.prototype` with `Object.freeze()`. Finally, it is always best to perform input validation with a a [JSON schema validator](https://github.com/ajv-validator/ajv), which could mitigate this issue entirely in many cases." + } + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "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.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.11]" + ], + "cves": [ + { + "id": "CVE-2018-16487", + "cvssV2": "6.8", + "cvssV3": "5.6", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "evidence": [ + { + "file": "server.js", + "startLine": 4, + "startColumn": 1, + "endLine": 4, + "endColumn": 32, + "snippet": "Object.freeze(Object.prototype)", + "reason": "Prototype pollution `Object.freeze` remediation was detected" + } + ] + } + } + ], + "issueId": "XRAY-75300", + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2018-16487", + "https://www.npmjs.com/advisories/782", + "https://security.netapp.com/advisory/ntap-20190919-0004/", + "https://github.com/advisories/GHSA-4xc9-xhrj-v574", + "https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad", + "https://security.netapp.com/advisory/ntap-20190919-0004", + "https://hackerone.com/reports/380873" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "High", + "summary": "Insufficient input validation in the Lodash library leads to prototype pollution.", + "details": "The [Lodash](https://lodash.com/) library is an open-source JavaScript project that simplifies operations on string, arrays, numbers, and other objects. It is widely used in connected devices. \n\nThe `merge`, `mergeWith`, and `defaultsDeep` methods in Lodash are vulnerable to [prototype pollution](https://shieldfy.io/security-wiki/prototype-pollution/introduction-to-prototype-pollution/). Attackers can exploit this vulnerability by specifying a crafted `sources` parameter to any of these methods, which can modify the prototype properties of the `Object`, `Function`, `Array`, `String`, `Number`, and `Boolean` objects. A public [exploit](https://hackerone.com/reports/380873) exists which performs the prototype pollution with an arbitrary key and value.\n\nThe library implementation has a bug in the `safeGet()` function in the `lodash.js` module that allows for adding or modifying `prototype` properties of various objects. The official [solution](https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad) fixes the bug by explicitly forbidding the addition or modification of `prototype` properties.\n\nA related CVE (CVE-2018-3721) covers the same issue prior to Lodash version 4.17.5, but the fix for that was incomplete.", + "severityReasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find remote input that propagates into one of the following methods - \n* `merge` - 2nd argument\n* `mergeWith` - 2nd argument\n* `defaultsDeep` - 2nd argument", + "isPositive": true + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "A public PoC demonstrated exploitation by injecting an attacker controlled key and value into the prototype" + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." + } + }, + { + "severity": "Medium", + "impactedPackageName": "ejs", + "impactedPackageVersion": "3.1.6", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[3.1.10]" + ], + "cves": [ + { + "id": "CVE-2024-33883", + "cvssV2": "", + "cvssV3": "4.0", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `ejs.compile()` is called." + } + } + ], + "issueId": "XRAY-599735", + "references": [ + "https://security.netapp.com/advisory/ntap-20240605-0003/", + "https://security.netapp.com/advisory/ntap-20240605-0003", + "https://github.com/mde/ejs/commit/e469741dca7df2eb400199e1cdb74621e3f89aa5", + "https://github.com/mde/ejs/compare/v3.1.9...v3.1.10", + "https://github.com/advisories/GHSA-ghr5-ch3p-vcr6", + "https://nvd.nist.gov/vuln/detail/CVE-2024-33883" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "ejs", + "version": "3.1.6" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Insufficient input validation in EJS may lead to prototype pollution.", + "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as `EJS`, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nA prototype pollution gadget within the EJS template engine could potentially be leveraged by attackers to achieve remote code execution or DoS via prototype pollution.\n\n```\nfunction Template(text, opts) {\n opts = opts || utils.createNullProtoObjWherePossible();\n```\n\nWhen checking for the presence of a property within an object variable, the lookup scope isn't explicitly defined. In JavaScript, the absence of a defined lookup scope prompts a search up to the root prototype (`Object.prototype`). This could potentially be under the control of an attacker if another prototype pollution vulnerability is present within the application.\n\nIf the application server is using the EJS as the backend template engine, and there is another prototype pollution vulnerability in the application, then the attacker could leverage the found gadgets in the EJS template engine to escalate the prototype pollution to remote code execution or DoS.\n\nThe following code will execute a command on the server by polluting `opts.escapeFunction`:\n \n```\nconst express = require('express');\nconst app = express();\nconst port = 8008;\nconst ejs = require('ejs');\n\n// Set EJS as the view engine\napp.set('view engine', 'ejs');\n\napp.get('/', (req, res) =\u003e {\n \n const data = {title: 'Welcome', message: 'Hello'};\n\n // Sample EJS template string\n const templateString = `\u003chtml\u003e\u003chead\u003e\u003ctitle\u003e\u003c%= title %\u003e\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003ch1\u003e\u003c%= message %\u003e\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e`;\n\n const { exec } = require('child_process');\n\n function myFunc() {\n exec('bash -c \"echo 123\"', (error, stdout, stderr) =\u003e {\n if (error) {\n console.error(`exec error: ${error}`);\n return;\n }\n if (stderr){\n console.log(`stderr : ${stderr}`);\n return;\n }\n // Handle success\n console.log(`Command executed successfully. Output: ${stdout}`);\n });\n }\n\n const options = {client:false};\n\n Object.prototype.escapeFunction = myFunc;\n \n const compiledTemplate = ejs.compile(templateString, options);\n const renderedHtml = compiledTemplate(data);\n res.send(renderedHtml);\n});\n\n// Start the server\napp.listen(port, () =\u003e {\n console.log(`Server is running on http://localhost:${port}`);\n});\n```", + "severityReasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "Attackers can only leverage this vulnerability when the application server is using the EJS as the backend template engine. Moreover, there must be a second prototype pollution vulnerability in the application.", + "isPositive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "CVSS does not take into account the unlikely prerequisites necessary for exploitation.", + "isPositive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "A prototype pollution attack allows the attacker to inject new properties into all JavaScript objects.\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable." + } + ] + } + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.21]" + ], + "cves": [ + { + "id": "CVE-2020-28500", + "cvssV2": "5.0", + "cvssV3": "5.3", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." + } + } + ], + "issueId": "XRAY-140562", + "references": [ + "https://cert-portal.siemens.com/productcert/pdf/ssa-637483.pdf", + "https://github.com/lodash/lodash/commit/c4847ebe7d14540bb28a8b932a9ce1b9ecbfee1a", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARS-1074894", + "https://github.com/lodash/lodash/blob/npm/trimEnd.js%23L8", + "https://security.netapp.com/advisory/ntap-20210312-0006/", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1074893", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWER-1074892", + "https://www.oracle.com//security-alerts/cpujul2021.html", + "https://www.oracle.com/security-alerts/cpuoct2021.html", + "https://nvd.nist.gov/vuln/detail/CVE-2020-28500", + "https://www.oracle.com/security-alerts/cpujul2022.html", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWERGITHUBLODASH-1074895", + "https://github.com/lodash/lodash/pull/5065/commits/02906b8191d3c100c193fe6f7b27d1c40f200bb7", + "https://www.oracle.com/security-alerts/cpujan2022.html", + "https://github.com/advisories/GHSA-29mw-wpgm-hmr9", + "https://github.com/lodash/lodash/pull/5065", + "https://snyk.io/vuln/SNYK-JAVA-ORGFUJIONWEBJARS-1074896", + "https://snyk.io/vuln/SNYK-JS-LODASH-1018905" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "ReDoS in lodash could lead to a denial of service when handling untrusted strings.", + "details": "JavaScript-based applications that use [lodash](https://github.com/lodash/lodash) and specifically the [_.toNumber](https://lodash.com/docs/4.17.15#toNumber), [_.trim](https://lodash.com/docs/4.17.15#trim) and [_.trimEnd](https://lodash.com/docs/4.17.15#trimEnd) functions, could be vulnerable to DoS (Denial of Service) through a faulty regular expression that introduces a ReDoS (Regular Expression DoS) vulnerability. This vulnerability is only triggered if untrusted user input flows into these vulnerable functions and the attacker can supply arbitrary long strings (over 50kB) that contain whitespaces. \n\nOn a modern Core i7-based system, calling the vulnerable functions with a 50kB string could take between 2 to 3 seconds to execute and 4.5 minutes for a longer 500kB string. The fix improved the regular expression performance so it took only a few milliseconds on the same Core i7-based system. This vulnerability is easily exploitable as all is required is to build a string that triggers it as can be seen in this PoC reproducing code - \n\n```js\nvar untrusted_user_input_50k = \"a\" + ' '.repeat(50000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_50k); // should take a few seconds to run\nvar untrusted_user_input_500k = \"a\" + ' '.repeat(500000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_500k); // should take a few minutes to run\n```", + "severityReasons": [ + { + "name": "The issue has an exploit published", + "description": "Public exploit demonstrated ReDoS" + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "Exploitation depends on parsing user input by the `.toNumber`, `.trim` or `.trimEnd` `lodash` functions, and requires the input to contain whitespaces and be very long (over 50KB)", + "isPositive": true + } + ], + "remediation": "##### Deployment mitigations\n\nTrim untrusted strings based on size before providing it to the vulnerable functions by using the `substring` function to with a fixed maximum size like so - ```js untrusted_user_input.substring(0, max_string_size_less_than_50kB); ```" + } + } + ], + "securityViolations": [ + { + "severity": "Critical", + "impactedPackageName": "ejs", + "impactedPackageVersion": "3.1.6", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "ejs v3.1.9 is vulnerable to server-side template injection. If the ejs file is controllable, template injection can be implemented through the configuration settings of the closeDelimiter parameter. NOTE: this is disputed by the vendor because the render function is not intended to be used with untrusted input.", + "applicable": "Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2023-29827", + "cvssV2": "", + "cvssV3": "9.8", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether any of the following conditions are met:\n\n1. The `ejs.renderFile` function is called with an unknown third argument.\n\n2. The `ejs.compile` function is called with an unknown second argument.\n\n3. The `express.set` function is called with any of the following arguments:\n\n* `express.set(\"view engine\", \"ejs\")`\n* `express.set(\"view engine\", {USER_INPUT})`\n* `express.set({USER_INPUT}, \"ejs\")`\n* `express.set({USER_INPUT}, {USER_INPUT})`", + "evidence": [ + { + "file": "server.js", + "startLine": 14, + "startColumn": 1, + "endLine": 14, + "endColumn": 30, + "snippet": "app.set('view engine', 'ejs')", + "reason": "The vulnerable functionality is triggered since express.set is called with 'view engine' as the first argument and 'ejs' as the second argument or both arguments with external input" + } + ] + } + } + ], + "issueId": "XRAY-520200", + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2023-29827", + "https://github.com/mde/ejs/issues/720", + "https://github.com/mde/ejs/blob/main/SECURITY.md#out-of-scope-vulnerabilities" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "ejs", + "version": "3.1.6" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Low", + "summary": "Insufficient input validation can lead to template injection in ejs when attackers can control both the rendered template and rendering options.", + "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to bypass ejs' template injection restrictions, by abusing the `closeDelimiter` rendering option, in the case when -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\n\nThe vulnerability was **rightfully disputed** due to the fact that a vulnerable configuration is extremely unlikely to exist in any real-world setup. As such, the maintainers will not provide a fix for this (non-)issue.\n\nExample of a vulnerable application -\n```js\nconst express = require('express')\nconst app = express()\nconst port = 3000\n\napp.set('view engine', 'ejs');\n\napp.get('/page', (req,res) =\u003e {\n res.render('page', req.query); // OPTS (2nd parameter) IS ATTACKER-CONTROLLED\n})\n\napp.listen(port, () =\u003e {\n console.log(\"Example app listening on port ${port}\")\n})\n```\n\nContents of `page.ejs` (very unlikely to be attacker controlled) -\n```js\n%%1\");process.mainModule.require('child_process').execSync('calc');//\n```\n\nIn this case, sending `closeDelimiter` with the same malicious code that already exists at `page.ejs` will trigger the injection -\n`http://127.0.0.1:3000/page?settings[view%20options][closeDelimiter]=1\")%3bprocess.mainModule.require('child_process').execSync('calc')%3b//`", + "severityReasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS does not take into account the rarity of a vulnerable configuration to exist", + "isPositive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The vulnerability can be exploited only under the following conditions -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\nThis vulnerable configuration is extremely unlikely to exist in any real-world setup.", + "isPositive": true + }, + { + "name": "The issue has been disputed by the vendor", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "Published exploit demonstrates template injection" + } + ] + } + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "lodash prior to 4.17.11 is affected by: CWE-400: Uncontrolled Resource Consumption. The impact is: Denial of service. The component is: Date handler. The attack vector is: Attacker provides very long strings, which the library attempts to match using a regular expression. The fixed version is: 4.17.11.", + "applicable": "Not Covered", + "fixedVersions": [ + "[4.17.11]" + ], + "cves": [ + { + "id": "CVE-2019-1010266", + "cvssV2": "4.0", + "cvssV3": "6.5", + "applicability": { + "status": "Not Covered" + } + } + ], + "issueId": "XRAY-85049", + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2019-1010266", + "https://github.com/lodash/lodash/wiki/Changelog", + "https://snyk.io/vuln/SNYK-JS-LODASH-73639", + "https://security.netapp.com/advisory/ntap-20190919-0004", + "https://security.netapp.com/advisory/ntap-20190919-0004/", + "https://github.com/lodash/lodash/issues/3359", + "https://github.com/lodash/lodash/commit/5c08f18d365b64063bfbfa686cbb97cdd6267347" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, merge, and mergeWith functions, which allows a malicious user to modify the prototype of \"Object\" via __proto__, causing the addition or modification of an existing property that will exist on all objects.", + "applicable": "Not Covered", + "fixedVersions": [ + "[4.17.5]" + ], + "cves": [ + { + "id": "CVE-2018-3721", + "cvssV2": "4.0", + "cvssV3": "6.5", + "applicability": { + "status": "Not Covered" + } + } + ], + "issueId": "XRAY-72918", + "references": [ + "https://www.npmjs.com/advisories/577", + "https://hackerone.com/reports/310443", + "https://github.com/advisories/GHSA-fvqr-27wr-82fm", + "https://nvd.nist.gov/vuln/detail/CVE-2018-3721", + "https://security.netapp.com/advisory/ntap-20190919-0004", + "https://security.netapp.com/advisory/ntap-20190919-0004/", + "https://github.com/lodash/lodash/commit/d8e069cc3410082e44eb18fcf8e7f3d08ebe1d4a" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Medium", + "impactedPackageName": "express", + "impactedPackageVersion": "4.18.2", + "impactedPackageType": "npm", + "components": [ + { + "name": "express", + "version": "4.18.2", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", + "applicable": "Not Covered", + "fixedVersions": [ + "[4.19.2]", + "[5.0.0-beta.3]" + ], + "cves": [ + { + "id": "CVE-2024-29041", + "cvssV2": "", + "cvssV3": "6.1", + "applicability": { + "status": "Not Covered" + } + } + ], + "issueId": "XRAY-594935", + "references": [ + "https://github.com/koajs/koa/issues/1800", + "https://github.com/expressjs/express/pull/5539", + "https://github.com/expressjs/express/commit/0b746953c4bd8e377123527db11f9cd866e39f94", + "https://github.com/expressjs/express/commit/0867302ddbde0e9463d0564fea5861feb708c2dd", + "https://github.com/advisories/GHSA-rv95-896h-c2vc", + "https://expressjs.com/en/4x/api.html#res.location", + "https://nvd.nist.gov/vuln/detail/CVE-2024-29041", + "https://github.com/expressjs/express/security/advisories/GHSA-rv95-896h-c2vc" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "express", + "version": "4.18.2" + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Critical", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.12]" + ], + "cves": [ + { + "id": "CVE-2019-10744", + "cvssV2": "6.4", + "cvssV3": "9.1", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `defaultsDeep` is called with external input to its 2nd (`sources`) argument, and the `Object.freeze()` remediation is not present.", + "evidence": [ + { + "file": "server.js", + "startLine": 4, + "startColumn": 1, + "endLine": 4, + "endColumn": 32, + "snippet": "Object.freeze(Object.prototype)", + "reason": "Prototype pollution `Object.freeze` remediation was detected" + } + ] + } + } + ], + "issueId": "XRAY-85679", + "references": [ + "https://www.npmjs.com/advisories/1065", + "https://github.com/lodash/lodash/pull/4336", + "https://www.oracle.com/security-alerts/cpujan2021.html", + "https://security.netapp.com/advisory/ntap-20191004-0005/", + "https://snyk.io/vuln/SNYK-JS-LODASH-450202", + "https://support.f5.com/csp/article/K47105354?utm_source=f5support\u0026amp;utm_medium=RSS", + "https://access.redhat.com/errata/RHSA-2019:3024", + "https://www.oracle.com/security-alerts/cpuoct2020.html", + "https://support.f5.com/csp/article/K47105354?utm_source=f5support\u0026amp%3Butm_medium=RSS", + "https://github.com/advisories/GHSA-jf85-cpcp-j695", + "https://nvd.nist.gov/vuln/detail/CVE-2019-10744" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "High", + "summary": "Insufficient input validation in lodash defaultsDeep() leads to prototype pollution.", + "details": "[lodash](https://www.npmjs.com/package/lodash) is a modern JavaScript utility library delivering modularity, performance, \u0026 extras.\n\nThe function `defaultsDeep` was found to be vulnerable to prototype pollution, when accepting arbitrary source objects from untrusted input\n\nExample of code vulnerable to this issue - \n```js\nconst lodash = require('lodash'); \nconst evilsrc = {constructor: {prototype: {evilkey: \"evilvalue\"}}};\nlodash.defaultsDeep({}, evilsrc)\n```", + "severityReasons": [ + { + "name": "The issue has an exploit published", + "description": "A public PoC demonstrates exploitation of this issue" + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", + "isPositive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find remote input that propagates into the `defaultsDeep` method (2nd arg)", + "isPositive": true + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." + } + }, + { + "severity": "Critical", + "impactedPackageName": "ejs", + "impactedPackageVersion": "3.1.6", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "The ejs (aka Embedded JavaScript templates) package 3.1.6 for Node.js allows server-side template injection in settings[view options][outputFunctionName]. This is parsed as an internal option, and overwrites the outputFunctionName option with an arbitrary OS command (which is executed upon template compilation).", + "applicable": "Not Applicable", + "fixedVersions": [ + "[3.1.7]" + ], + "cves": [ + { + "id": "CVE-2022-29078", + "cvssV2": "7.5", + "cvssV3": "9.8", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks for two vulnerable flows:\n\n1. Whether the `express.set` function is called with the arguments: `view engine` and `ejs`, or external input and if it's followed by a call to the vulnerable function `render` with an unknown second argument.\n\n2. Whether the `renderFile` function is called with an unknown second argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "evidence": [ + { + "file": "server.js", + "startLine": 4, + "startColumn": 1, + "endLine": 4, + "endColumn": 32, + "snippet": "Object.freeze(Object.prototype)", + "reason": "Prototype pollution `Object.freeze` remediation was detected" + } + ] + } + } + ], + "issueId": "XRAY-209002", + "references": [ + "https://github.com/mde/ejs/commit/15ee698583c98dadc456639d6245580d17a24baf", + "https://eslam.io/posts/ejs-server-side-template-injection-rce/", + "https://security.netapp.com/advisory/ntap-20220804-0001", + "https://github.com/mde/ejs/releases", + "https://nvd.nist.gov/vuln/detail/CVE-2022-29078", + "https://eslam.io/posts/ejs-server-side-template-injection-rce", + "https://github.com/mde/ejs", + "https://security.netapp.com/advisory/ntap-20220804-0001/" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "ejs", + "version": "3.1.6" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Insufficient input validation in EJS enables attackers to perform template injection when attacker can control the rendering options.", + "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to perform template injection on the `opts.outputFunctionName` variable, since the variable is injected into the template body without any escaping. Although it is unlikely that the attacker can directly control the `outputFunctionName` property, it is possible that it can be influenced in conjunction with a prototype pollution vulnerability.\n\nOnce template injection is achieved, the attacker can immediately perform remote code execution since the template engine (EJS) allows executing arbitrary JavaScript code.\n\nExample of a vulnerable Node.js application -\n```js\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst lodash = require('lodash');\nconst ejs = require('ejs');\n\nconst app = express();\n\napp\n .use(bodyParser.urlencoded({extended: true}))\n .use(bodyParser.json());\n\napp.set('views', './');\napp.set('view engine', 'ejs');\n\napp.get(\"/\", (req, res) =\u003e {\n res.render('index');\n});\n\napp.post(\"/\", (req, res) =\u003e {\n let data = {};\n let input = JSON.parse(req.body.content);\n lodash.defaultsDeep(data, input);\n res.json({message: \"OK\"});\n});\n\nlet server = app.listen(8086, '0.0.0.0', function() {\n console.log('Listening on port %d', server.address().port);\n});\n```\n\nExploiting the above example for RCE -\n`curl 127.0.0.1:8086 -v --data 'content={\"constructor\": {\"prototype\": {\"outputFunctionName\": \"a; return global.process.mainModule.constructor._load(\\\"child_process\\\").execSync(\\\"whoami\\\"); //\"}}}'\n`\n\nDue to the prototype pollution in the `lodash.defaultsDeep` call, an attacker can inject the `outputFunctionName` property with an arbitrary value. The chosen value executes an arbitrary process via the `child_process` module.", + "severityReasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker has to find a way to get their malicious input to `opts.outputFunctionName`, which will usually require exploitation of a prototype pollution vulnerability somewhere else in the code. However, there could be cases where the attacker can pass malicious data to the render function directly because of design problems in other code using EJS.", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "There are multiple examples of exploits for this vulnerability online." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Successful exploitation of this vulnerability leads to remote code execution." + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\nNote that this mitigation is supposed to stop any prototype pollution attacks which can allow an attacker to control the `opts.outputFunctionName` parameter indirectly.\n\nThe mitigation will not stop any (extremely unlikely) scenarios where the JavaScript code allows external input to directly affect `opts.outputFunctionName`." + } + }, + { + "severity": "High", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "Lodash versions prior to 4.17.21 are vulnerable to Command Injection via the template function.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.21]" + ], + "cves": [ + { + "id": "CVE-2021-23337", + "cvssV2": "6.5", + "cvssV3": "7.2", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `lodash.template` is called with external input to its 2nd (`options`) argument." + } + } + ], + "issueId": "XRAY-140575", + "references": [ + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1074929", + "https://security.netapp.com/advisory/ntap-20210312-0006/", + "https://snyk.io/vuln/SNYK-JS-LODASH-1040724", + "https://security.netapp.com/advisory/ntap-20210312-0006", + "https://www.oracle.com/security-alerts/cpujan2022.html", + "https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c", + "https://cert-portal.siemens.com/productcert/pdf/ssa-637483.pdf", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWER-1074928", + "https://www.oracle.com/security-alerts/cpuoct2021.html", + "https://snyk.io/vuln/SNYK-JAVA-ORGFUJIONWEBJARS-1074932", + "https://github.com/lodash/lodash/blob/ddfd9b11a0126db2302cb70ec9973b66baec0975/lodash.js%23L14851", + "https://github.com/advisories/GHSA-35jh-r3h4-6jhm", + "https://www.oracle.com/security-alerts/cpujul2022.html", + "https://www.oracle.com//security-alerts/cpujul2021.html", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARS-1074930", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWERGITHUBLODASH-1074931", + "https://nvd.nist.gov/vuln/detail/CVE-2021-23337", + "https://github.com/lodash/lodash/blob/ddfd9b11a0126db2302cb70ec9973b66baec0975/lodash.js#L14851" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Improper sanitization in the lodash template function leads to JavaScript code injection through the options argument.", + "details": "JavaScript-based applications (both frontend and backend) that use the [template function](https://lodash.com/docs/4.17.15#template) -`_.template([string=''], [options={}])` from the [lodash](https://lodash.com/) utility library and provide the `options` argument (specifically the `variable` option) from untrusted user input, are vulnerable to JavaScript code injection. This issue can be easily exploited, and an exploitation example is [publicly available](https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c#diff-a561630bb56b82342bc66697aee2ad96efddcbc9d150665abd6fb7ecb7c0ab2fR22303) in the fix tests that was introduced in version 4.17.21 - \n```js\nlodash.template('', { variable: '){console.log(process.env)}; with(obj' })()\n```", + "severityReasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "It is highly unlikely that a JS program will accept arbitrary remote input into the template's `options` argument", + "isPositive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must find remote input that propagates into the `options` argument of a `template` call", + "isPositive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Leads to remote code execution through JS code injection" + }, + { + "name": "The issue has an exploit published", + "description": "Published exploit demonstrates arbitrary JS code execution" + } + ] + } + }, + { + "severity": "High", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "Prototype pollution attack when using _.zipObjectDeep in lodash before 4.17.20.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.19]" + ], + "cves": [ + { + "id": "CVE-2020-8203", + "cvssV2": "5.8", + "cvssV3": "7.4", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `zipObjectDeep` is called with external input to its 1st (`props`) and 2nd (`values`) arguments, and the `Object.freeze()` remediation is not present." + } + } + ], + "issueId": "XRAY-114089", + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2020-8203", + "https://www.oracle.com/security-alerts/cpuapr2022.html", + "https://hackerone.com/reports/864701", + "https://hackerone.com/reports/712065", + "https://github.com/advisories/GHSA-p6mc-m468-83gw", + "https://www.oracle.com//security-alerts/cpujul2021.html", + "https://github.com/lodash/lodash/issues/4744", + "https://www.oracle.com/security-alerts/cpuApr2021.html", + "https://github.com/github/advisory-database/pull/2884", + "https://www.oracle.com/security-alerts/cpujan2022.html", + "https://github.com/lodash/lodash/commit/c84fe82760fb2d3e03a63379b297a1cc1a2fce12", + "https://security.netapp.com/advisory/ntap-20200724-0006/", + "https://web.archive.org/web/20210914001339/https://github.com/lodash/lodash/issues/4744", + "https://www.oracle.com/security-alerts/cpuoct2021.html", + "https://github.com/lodash/lodash/issues/4874", + "https://github.com/lodash/lodash/wiki/Changelog#v41719" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Critical", + "summary": "Prototype pollution in lodash object merging and zipping functions leads to code injection.", + "details": "[lodash](https://lodash.com/) is a JavaScript library which provides utility functions for common programming tasks.\n\nJavaScript frontend and Node.js-based backend applications that merge or zip objects using the lodash functions `mergeWith`, `merge` and `zipObjectDeep` are vulnerable to [prototype pollution](https://medium.com/node-modules/what-is-prototype-pollution-and-why-is-it-such-a-big-deal-2dd8d89a93c) if one or more of the objects it receives as arguments are obtained from user input. \nAn attacker controlling this input given to the vulnerable functions can inject properties to JavaScript special objects such as [Object.prototype](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes) from which all JavaScript objects inherit properties and methods. Any change on `Object.prototype` properties will then propagate through the prototype chain inheritance to all of the objects in a JavaScript application. This in turn would allow an attacker to add new properties or modify existing properties which will have application specific implications that could lead to DoS (denial of service), authentication bypass, privilege escalation and even RCE (remote code execution) in [some cases](https://youtu.be/LUsiFV3dsK8?t=1152). \nAs an example for privilege escalation, consider a JavaScript application that has a `user` object which has a Boolean property of `user.isAdmin` which is used to decide which actions the user may take. If an attacker can modify or add the `isAdmin` property through prototype pollution, it can escalate the privileges of its own user to those of an admin. \nAs exploitation is usually application specific, successful exploitation is much more likely if an attacker have access to the JavaScript application code. As such, frontend applications are more vulnerable to this vulnerability than Node.js backend applications.", + "severityReasons": [ + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "isPositive": true + }, + { + "name": "The issue can be exploited by attackers over the network" + }, + { + "name": "The issue is trivial to exploit and does not require a published writeup or PoC" + } + ], + "remediation": "##### Deployment mitigations\n\nAs general guidelines against prototype pollution, first consider not merging objects originating from user input or using a Map structure instead of an object. If merging objects is needed, look into creating objects without a prototype with `Object.create(null)` or into freezing `Object.prototype` with `Object.freeze()`. Finally, it is always best to perform input validation with a a [JSON schema validator](https://github.com/ajv-validator/ajv), which could mitigate this issue entirely in many cases." + } + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "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.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.11]" + ], + "cves": [ + { + "id": "CVE-2018-16487", + "cvssV2": "6.8", + "cvssV3": "5.6", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.merge` with external input to its 2nd (`sources`) argument.\n* `lodash.mergeWith` with external input to its 2nd (`sources`) argument.\n* `lodash.defaultsDeep` with external input to its 2nd (`sources`) argument.\n\nThe scanner also checks whether the `Object.freeze()` remediation is not present.", + "evidence": [ + { + "file": "server.js", + "startLine": 4, + "startColumn": 1, + "endLine": 4, + "endColumn": 32, + "snippet": "Object.freeze(Object.prototype)", + "reason": "Prototype pollution `Object.freeze` remediation was detected" + } + ] + } + } + ], + "issueId": "XRAY-75300", + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2018-16487", + "https://www.npmjs.com/advisories/782", + "https://security.netapp.com/advisory/ntap-20190919-0004/", + "https://github.com/advisories/GHSA-4xc9-xhrj-v574", + "https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad", + "https://security.netapp.com/advisory/ntap-20190919-0004", + "https://hackerone.com/reports/380873" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "High", + "summary": "Insufficient input validation in the Lodash library leads to prototype pollution.", + "details": "The [Lodash](https://lodash.com/) library is an open-source JavaScript project that simplifies operations on string, arrays, numbers, and other objects. It is widely used in connected devices. \n\nThe `merge`, `mergeWith`, and `defaultsDeep` methods in Lodash are vulnerable to [prototype pollution](https://shieldfy.io/security-wiki/prototype-pollution/introduction-to-prototype-pollution/). Attackers can exploit this vulnerability by specifying a crafted `sources` parameter to any of these methods, which can modify the prototype properties of the `Object`, `Function`, `Array`, `String`, `Number`, and `Boolean` objects. A public [exploit](https://hackerone.com/reports/380873) exists which performs the prototype pollution with an arbitrary key and value.\n\nThe library implementation has a bug in the `safeGet()` function in the `lodash.js` module that allows for adding or modifying `prototype` properties of various objects. The official [solution](https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad) fixes the bug by explicitly forbidding the addition or modification of `prototype` properties.\n\nA related CVE (CVE-2018-3721) covers the same issue prior to Lodash version 4.17.5, but the fix for that was incomplete.", + "severityReasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find remote input that propagates into one of the following methods - \n* `merge` - 2nd argument\n* `mergeWith` - 2nd argument\n* `defaultsDeep` - 2nd argument", + "isPositive": true + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "A prototype pollution attack allows the attacker to inject new properties to all JavaScript objects (but not set existing properties).\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable.", + "isPositive": true + }, + { + "name": "The issue has an exploit published", + "description": "A public PoC demonstrated exploitation by injecting an attacker controlled key and value into the prototype" + } + ], + "remediation": "##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks." + } + }, + { + "severity": "Medium", + "impactedPackageName": "ejs", + "impactedPackageVersion": "3.1.6", + "impactedPackageType": "npm", + "components": [ + { + "name": "ejs", + "version": "3.1.6", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "The ejs (aka Embedded JavaScript templates) package before 3.1.10 for Node.js lacks certain pollution protection.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[3.1.10]" + ], + "cves": [ + { + "id": "CVE-2024-33883", + "cvssV2": "", + "cvssV3": "4.0", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `ejs.compile()` is called." + } + } + ], + "issueId": "XRAY-599735", + "references": [ + "https://security.netapp.com/advisory/ntap-20240605-0003/", + "https://security.netapp.com/advisory/ntap-20240605-0003", + "https://github.com/mde/ejs/commit/e469741dca7df2eb400199e1cdb74621e3f89aa5", + "https://github.com/mde/ejs/compare/v3.1.9...v3.1.10", + "https://github.com/advisories/GHSA-ghr5-ch3p-vcr6", + "https://nvd.nist.gov/vuln/detail/CVE-2024-33883" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "ejs", + "version": "3.1.6" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Insufficient input validation in EJS may lead to prototype pollution.", + "details": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as `EJS`, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nA prototype pollution gadget within the EJS template engine could potentially be leveraged by attackers to achieve remote code execution or DoS via prototype pollution.\n\n```\nfunction Template(text, opts) {\n opts = opts || utils.createNullProtoObjWherePossible();\n```\n\nWhen checking for the presence of a property within an object variable, the lookup scope isn't explicitly defined. In JavaScript, the absence of a defined lookup scope prompts a search up to the root prototype (`Object.prototype`). This could potentially be under the control of an attacker if another prototype pollution vulnerability is present within the application.\n\nIf the application server is using the EJS as the backend template engine, and there is another prototype pollution vulnerability in the application, then the attacker could leverage the found gadgets in the EJS template engine to escalate the prototype pollution to remote code execution or DoS.\n\nThe following code will execute a command on the server by polluting `opts.escapeFunction`:\n \n```\nconst express = require('express');\nconst app = express();\nconst port = 8008;\nconst ejs = require('ejs');\n\n// Set EJS as the view engine\napp.set('view engine', 'ejs');\n\napp.get('/', (req, res) =\u003e {\n \n const data = {title: 'Welcome', message: 'Hello'};\n\n // Sample EJS template string\n const templateString = `\u003chtml\u003e\u003chead\u003e\u003ctitle\u003e\u003c%= title %\u003e\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003ch1\u003e\u003c%= message %\u003e\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e`;\n\n const { exec } = require('child_process');\n\n function myFunc() {\n exec('bash -c \"echo 123\"', (error, stdout, stderr) =\u003e {\n if (error) {\n console.error(`exec error: ${error}`);\n return;\n }\n if (stderr){\n console.log(`stderr : ${stderr}`);\n return;\n }\n // Handle success\n console.log(`Command executed successfully. Output: ${stdout}`);\n });\n }\n\n const options = {client:false};\n\n Object.prototype.escapeFunction = myFunc;\n \n const compiledTemplate = ejs.compile(templateString, options);\n const renderedHtml = compiledTemplate(data);\n res.send(renderedHtml);\n});\n\n// Start the server\napp.listen(port, () =\u003e {\n console.log(`Server is running on http://localhost:${port}`);\n});\n```", + "severityReasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "Attackers can only leverage this vulnerability when the application server is using the EJS as the backend template engine. Moreover, there must be a second prototype pollution vulnerability in the application.", + "isPositive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "CVSS does not take into account the unlikely prerequisites necessary for exploitation.", + "isPositive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "A prototype pollution attack allows the attacker to inject new properties into all JavaScript objects.\nTherefore, the impact of a prototype pollution attack depends on the way the JavaScript code uses any object properties after the attack is triggered.\nUsually, a DoS attack is possible since invalid properties quickly lead to an exception being thrown. In more severe cases, RCE may be achievable." + } + ] + } + }, + { + "severity": "Medium", + "impactedPackageName": "lodash", + "impactedPackageVersion": "4.17.0", + "impactedPackageType": "npm", + "components": [ + { + "name": "lodash", + "version": "4.17.0", + "location": { + "file": "/Users/user/ejs-frog-demo/package.json" + } + } + ], + "summary": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", + "applicable": "Not Applicable", + "fixedVersions": [ + "[4.17.21]" + ], + "cves": [ + { + "id": "CVE-2020-28500", + "cvssV2": "5.0", + "cvssV3": "5.3", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n* `lodash.trim` with external input to its 1st (`string`) argument.\n* `lodash.toNumber` with external input to its 1st (`value`) argument.\n* `lodash.trimEnd` with external input to its 1st (`string`) argument." + } + } + ], + "issueId": "XRAY-140562", + "references": [ + "https://cert-portal.siemens.com/productcert/pdf/ssa-637483.pdf", + "https://github.com/lodash/lodash/commit/c4847ebe7d14540bb28a8b932a9ce1b9ecbfee1a", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARS-1074894", + "https://github.com/lodash/lodash/blob/npm/trimEnd.js%23L8", + "https://security.netapp.com/advisory/ntap-20210312-0006/", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1074893", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWER-1074892", + "https://www.oracle.com//security-alerts/cpujul2021.html", + "https://www.oracle.com/security-alerts/cpuoct2021.html", + "https://nvd.nist.gov/vuln/detail/CVE-2020-28500", + "https://www.oracle.com/security-alerts/cpujul2022.html", + "https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWERGITHUBLODASH-1074895", + "https://github.com/lodash/lodash/pull/5065/commits/02906b8191d3c100c193fe6f7b27d1c40f200bb7", + "https://www.oracle.com/security-alerts/cpujan2022.html", + "https://github.com/advisories/GHSA-29mw-wpgm-hmr9", + "https://github.com/lodash/lodash/pull/5065", + "https://snyk.io/vuln/SNYK-JAVA-ORGFUJIONWEBJARS-1074896", + "https://snyk.io/vuln/SNYK-JS-LODASH-1018905" + ], + "impactPaths": [ + [ + { + "name": "froghome", + "version": "1.0.0" + }, + { + "name": "lodash", + "version": "4.17.0" + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "ReDoS in lodash could lead to a denial of service when handling untrusted strings.", + "details": "JavaScript-based applications that use [lodash](https://github.com/lodash/lodash) and specifically the [_.toNumber](https://lodash.com/docs/4.17.15#toNumber), [_.trim](https://lodash.com/docs/4.17.15#trim) and [_.trimEnd](https://lodash.com/docs/4.17.15#trimEnd) functions, could be vulnerable to DoS (Denial of Service) through a faulty regular expression that introduces a ReDoS (Regular Expression DoS) vulnerability. This vulnerability is only triggered if untrusted user input flows into these vulnerable functions and the attacker can supply arbitrary long strings (over 50kB) that contain whitespaces. \n\nOn a modern Core i7-based system, calling the vulnerable functions with a 50kB string could take between 2 to 3 seconds to execute and 4.5 minutes for a longer 500kB string. The fix improved the regular expression performance so it took only a few milliseconds on the same Core i7-based system. This vulnerability is easily exploitable as all is required is to build a string that triggers it as can be seen in this PoC reproducing code - \n\n```js\nvar untrusted_user_input_50k = \"a\" + ' '.repeat(50000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_50k); // should take a few seconds to run\nvar untrusted_user_input_500k = \"a\" + ' '.repeat(500000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_500k); // should take a few minutes to run\n```", + "severityReasons": [ + { + "name": "The issue has an exploit published", + "description": "Public exploit demonstrated ReDoS" + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "Exploitation depends on parsing user input by the `.toNumber`, `.trim` or `.trimEnd` `lodash` functions, and requires the input to contain whitespaces and be very long (over 50KB)", + "isPositive": true + } + ], + "remediation": "##### Deployment mitigations\n\nTrim untrusted strings based on size before providing it to the vulnerable functions by using the `substring` function to with a fixed maximum size like so - ```js untrusted_user_input.substring(0, max_string_size_less_than_50kB); ```" + } + } + ], + "licensesViolations": null, + "licenses": null, + "operationalRiskViolations": null, + "secrets": [ + { + "severity": "Medium", + "file": "server.js", + "startLine": 11, + "startColumn": 14, + "endLine": 11, + "endColumn": 24, + "snippet": "Sqc************", + "finding": "Secret keys were found", + "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + { + "severity": "Medium", + "file": "fake-creds.txt", + "startLine": 2, + "startColumn": 1, + "endLine": 2, + "endColumn": 11, + "snippet": "Sqc************", + "finding": "Secret keys were found", + "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + { + "severity": "Medium", + "file": "fake-creds.txt", + "startLine": 3, + "startColumn": 1, + "endLine": 3, + "endColumn": 11, + "snippet": "gho************", + "finding": "Secret keys were found", + "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + } + ], + "iacViolations": null, + "sastViolations": [ + { + "severity": "High", + "file": "server.js", + "startLine": 26, + "startColumn": 28, + "endLine": 26, + "endColumn": 37, + "snippet": "req.query", + "finding": "Template Object Injection", + "scannerDescription": "\n### Overview\nTemplate Object Injection (TOI) is a vulnerability that can occur in\nweb applications that use template engines to render dynamic content.\nTemplate engines are commonly used to generate HTML pages, emails, or\nother types of documents that include variable data. TOI happens when\nuntrusted user input is included as part of the template rendering\nprocess, and the template engine evaluates the input as a code\nexpression, leading to potential code injection or data tampering\nattacks. To prevent TOI vulnerabilities, it's important to sanitize and\nvalidate all user input that is used as part of the template rendering\nprocess.\n\n### Query operation\nIn this query we look for user inputs that flow directly to a\nrequest render.\n\n### Vulnerable example\n```javascript\nvar app = require('express')();\napp.set('view engine', 'hbs');\n\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n res.render('template', bodyParameter);\n});\n```\nIn this example, a user-provided data is injected directly into the\n`render` command, leading to potential code injection or data\ntampering attacks.\n\n### Remediation\n```diff\n+ const sanitizeHtml = require('sanitize-html');\nvar app = require('express')();\napp.set('view engine', 'hbs');\napp.use(require('body-parser').json());\napp.use(require('body-parser').urlencoded({ extended: false }));\napp.post('/path', function(req, res) {\n var bodyParameter = req.body.bodyParameter;\n var queryParameter = req.query.queryParameter;\n\n- res.render('template', bodyParameter);\n+ res.render('template', sanitizeHtml(bodyParameter));\n});\nUsing `sanitize-html`, the user-provided data is sanitized, before\nrendering to the response.\n```\n", + "codeFlow": [ + [ + { + "file": "server.js", + "startLine": 21, + "startColumn": 23, + "endLine": 21, + "endColumn": 26, + "snippet": "req" + }, + { + "file": "server.js", + "startLine": 26, + "startColumn": 28, + "endLine": 26, + "endColumn": 31, + "snippet": "req" + }, + { + "file": "server.js", + "startLine": 26, + "startColumn": 28, + "endLine": 26, + "endColumn": 37, + "snippet": "req.query" + } + ] + ] + }, + { + "severity": "Low", + "file": "server.js", + "startLine": 8, + "startColumn": 11, + "endLine": 8, + "endColumn": 20, + "snippet": "express()", + "finding": "Express Not Using Helmet", + "scannerDescription": "\n### Overview\nHelmet library should be used when using Express in order to properly configure\nHTTP header settings to mitigate a range of well-known vulnerabilities.\n\n### Remediation\n```javascript\nconst helmet = require(\"helmet\");\nconst app = express()\n\napp.use(helmet())\n```\n\n### References\n[Best practices for Express](https://expressjs.com/en/advanced/best-practice-security.html)\n" + }, + { + "severity": "Low", + "file": "public/js/bootstrap.js", + "startLine": 136, + "startColumn": 22, + "endLine": 136, + "endColumn": 35, + "snippet": "Math.random()", + "finding": "Use of Insecure Random", + "scannerDescription": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" + }, + { + "severity": "Low", + "file": "public/js/bootstrap.bundle.js", + "startLine": 135, + "startColumn": 22, + "endLine": 135, + "endColumn": 35, + "snippet": "Math.random()", + "finding": "Use of Insecure Random", + "scannerDescription": "\n### Overview\nA use of insecure random vulnerability is a type of security flaw that is\ncaused by the use of inadequate or predictable random numbers in a program\nor system. Random numbers are used in many security-related applications,\nsuch as generating cryptographic keys and if the numbers are not truly\nrandom, an attacker may be able to predict or recreate them, potentially\ncompromising the security of the system.\n\n### Vulnerable example\n```javascript\nvar randomNum = Math.random();\n```\n`Math.random` is not secured, as it creates predictable random numbers.\n\n### Remediation\n```diff\nvar randomNum = crypto.randomInt(0, 100)\n```\n`crypto.randomInt` is secured, and creates much less predictable random\nnumbers.\n" + } + ], + "errors": null +} diff --git a/tests/testdata/output/audit/audit_summary.json b/tests/testdata/output/audit/audit_summary.json new file mode 100644 index 00000000..58a813af --- /dev/null +++ b/tests/testdata/output/audit/audit_summary.json @@ -0,0 +1,67 @@ +{ + "scans": [ + { + "target": "", + "vulnerabilities": { + "sca": { + "scan_ids": [ + "711851ce-68c4-4dfd-7afb-c29737ebcb96" + ], + "security": { + "Critical": { + "Applicable": 1, + "Not Applicable": 2 + }, + "High": { + "Not Applicable": 2 + }, + "Medium": { + "Not Applicable": 3, + "Not Covered": 3 + }, + "Unknown": { + "Not Covered": 1 + } + } + }, + "iac": {}, + "secrets": { + "Medium": { + "": 3 + } + }, + "sast": { + "High": { + "": 1 + }, + "Low": { + "": 3 + } + } + }, + "violations": { + "watches": [ + "Security_watch_1" + ], + "sca": { + "scan_ids": [ + "711851ce-68c4-4dfd-7afb-c29737ebcb96" + ], + "security": { + "Critical": { + "Applicable": 1, + "Not Applicable": 2 + }, + "High": { + "Not Applicable": 2 + }, + "Medium": { + "Not Applicable": 3, + "Not Covered": 3 + } + } + } + } + } + ] +} \ No newline at end of file diff --git a/tests/testdata/other/output/jobSummary/binary_vulnerabilities.md b/tests/testdata/output/jobSummary/binary_vulnerabilities.md similarity index 100% rename from tests/testdata/other/output/jobSummary/binary_vulnerabilities.md rename to tests/testdata/output/jobSummary/binary_vulnerabilities.md diff --git a/tests/testdata/other/output/jobSummary/build_scan_vulnerabilities.md b/tests/testdata/output/jobSummary/build_scan_vulnerabilities.md similarity index 100% rename from tests/testdata/other/output/jobSummary/build_scan_vulnerabilities.md rename to tests/testdata/output/jobSummary/build_scan_vulnerabilities.md diff --git a/tests/testdata/other/output/jobSummary/docker_vulnerabilities.md b/tests/testdata/output/jobSummary/docker_vulnerabilities.md similarity index 100% rename from tests/testdata/other/output/jobSummary/docker_vulnerabilities.md rename to tests/testdata/output/jobSummary/docker_vulnerabilities.md diff --git a/tests/testdata/other/output/jobSummary/no_violations.md b/tests/testdata/output/jobSummary/no_violations.md similarity index 100% rename from tests/testdata/other/output/jobSummary/no_violations.md rename to tests/testdata/output/jobSummary/no_violations.md diff --git a/tests/testdata/other/output/jobSummary/no_vulnerabilities.md b/tests/testdata/output/jobSummary/no_vulnerabilities.md similarity index 100% rename from tests/testdata/other/output/jobSummary/no_vulnerabilities.md rename to tests/testdata/output/jobSummary/no_vulnerabilities.md diff --git a/tests/testdata/other/output/jobSummary/security_section.md b/tests/testdata/output/jobSummary/security_section.md similarity index 100% rename from tests/testdata/other/output/jobSummary/security_section.md rename to tests/testdata/output/jobSummary/security_section.md diff --git a/tests/testdata/other/output/jobSummary/violations.md b/tests/testdata/output/jobSummary/violations.md similarity index 100% rename from tests/testdata/other/output/jobSummary/violations.md rename to tests/testdata/output/jobSummary/violations.md diff --git a/tests/testdata/other/output/jobSummary/violations_not_defined.md b/tests/testdata/output/jobSummary/violations_not_defined.md similarity index 100% rename from tests/testdata/other/output/jobSummary/violations_not_defined.md rename to tests/testdata/output/jobSummary/violations_not_defined.md diff --git a/tests/testdata/other/output/jobSummary/violations_not_extended_view.md b/tests/testdata/output/jobSummary/violations_not_extended_view.md similarity index 100% rename from tests/testdata/other/output/jobSummary/violations_not_extended_view.md rename to tests/testdata/output/jobSummary/violations_not_extended_view.md diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index 3554694e..24aa5d14 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -275,12 +275,12 @@ func ReadSarifResults(t *testing.T, path string) *sarif.Report { return results } -func ReadSummaryResults(t *testing.T, path string) formats.SummaryResults { +func ReadSummaryResults(t *testing.T, path string) formats.ResultsSummary { content, err := os.ReadFile(path) assert.NoError(t, err) - var results formats.SummaryResults + var results formats.ResultsSummary if !assert.NoError(t, json.Unmarshal(content, &results)) { - return formats.SummaryResults{} + return formats.ResultsSummary{} } // replace paths separators for _, targetResults := range results.Scans { @@ -290,7 +290,7 @@ func ReadSummaryResults(t *testing.T, path string) formats.SummaryResults { } func getJasConvertedPath(pathToConvert string) string { - return fmt.Sprintf("file://%s", filepath.FromSlash(strings.TrimPrefix(pathToConvert, "file://"))) + return filepath.FromSlash(strings.TrimPrefix(pathToConvert, "file://")) } func CreateTestWatch(t *testing.T, policyName string, watchName, severity xrayUtils.Severity) (string, func()) { diff --git a/utils/formats/sarifutils/sarifutils.go b/utils/formats/sarifutils/sarifutils.go index fcfe24bd..6e5e2c9f 100644 --- a/utils/formats/sarifutils/sarifutils.go +++ b/utils/formats/sarifutils/sarifutils.go @@ -211,12 +211,6 @@ func GetRunsByToolName(report *sarif.Report, toolName string) (filteredRuns []*s return } -func GetResultRuleId(result *sarif.Result) string { - if result.RuleID == nil { - return "" - } - return *result.RuleID} - func SetResultMsgMarkdown(markdown string, result *sarif.Result) { result.Message.Markdown = &markdown } @@ -242,6 +236,18 @@ func GetResultRuleId(result *sarif.Result) string { return "" } +func GetResultProperty(key string, result *sarif.Result) string { + if result.Properties == nil { + return "" + } + if _, exists := result.Properties[key]; exists { + if _, ok := result.Properties[key].(string); ok { + return result.Properties[key].(string) + } + } + return "" +} + func IsFingerprintsExists(result *sarif.Result) bool { return len(result.Fingerprints) > 0 } @@ -433,6 +439,13 @@ func GetRuleShortDescription(rule *sarif.ReportingDescriptor) string { return "" } +func GetRuleFullDescriptionText(rule *sarif.ReportingDescriptor) string { + if rule.FullDescription != nil && rule.FullDescription.Text != nil { + return *rule.FullDescription.Text + } + return "" +} + func SetRuleShortDescriptionText(value string, rule *sarif.ReportingDescriptor) { if rule.ShortDescription == nil { rule.ShortDescription = sarif.NewMultiformatMessageString(value) diff --git a/utils/formats/summary.go b/utils/formats/summary.go index 4e16fe0c..60d1c2b0 100644 --- a/utils/formats/summary.go +++ b/utils/formats/summary.go @@ -29,6 +29,7 @@ type ResultsSummary struct { type ScanSummary struct { Target string `json:"target"` + Name string `json:"name,omitempty"` Vulnerabilities *ScanResultSummary `json:"vulnerabilities,omitempty"` Violations *ScanViolationsSummary `json:"violations,omitempty"` CuratedPackages *CuratedPackages `json:"curated,omitempty"` diff --git a/utils/jasutils/jasutils.go b/utils/jasutils/jasutils.go index ffd10352..d7eb12f3 100644 --- a/utils/jasutils/jasutils.go +++ b/utils/jasutils/jasutils.go @@ -4,6 +4,7 @@ import ( "strings" "github.com/gookit/color" + "github.com/jfrog/jfrog-cli-security/utils" ) const ( @@ -56,6 +57,20 @@ func (as ApplicabilityStatus) ToString(pretty bool) string { } } +func SubScanTypeToJasScanType(subScanType utils.SubScanType) JasScanType { + switch subScanType { + case utils.SastScan: + return Sast + case utils.IacScan: + return IaC + case utils.SecretsScan: + return Secrets + case utils.ContextualAnalysisScan: + return Applicability + } + return "" +} + func ConvertToApplicabilityStatus(status string) ApplicabilityStatus { switch status { case Applicable.String(): diff --git a/utils/results.go b/utils/results.go deleted file mode 100644 index bcee459b..00000000 --- a/utils/results.go +++ /dev/null @@ -1,134 +0,0 @@ -package utils - -import ( - "github.com/jfrog/gofrog/datastructures" - "github.com/jfrog/jfrog-cli-security/formats" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" - "github.com/jfrog/jfrog-cli-security/utils/techutils" - "github.com/jfrog/jfrog-client-go/xray/services" - "github.com/owenrumney/go-sarif/v2/sarif" -) - -type Results struct { - ResultType CommandType - ScaResults []*ScaScanResult - XrayVersion string - ScansErr error - - ExtendedScanResults *ExtendedScanResults - - MultiScanId string -} - -func NewAuditResults(resultType CommandType) *Results { - return &Results{ResultType: resultType, ExtendedScanResults: &ExtendedScanResults{}} -} - -func (r *Results) GetScaScansXrayResults() (results []services.ScanResponse) { - for _, scaResult := range r.ScaResults { - results = append(results, scaResult.XrayResults...) - } - return -} - -func (r *Results) GetScaScannedTechnologies() []techutils.Technology { - technologies := datastructures.MakeSet[techutils.Technology]() - for _, scaResult := range r.ScaResults { - technologies.Add(scaResult.Technology) - } - return technologies.ToSlice() -} - -func (r *Results) IsMultipleProject() bool { - if len(r.ScaResults) == 0 { - return false - } - if len(r.ScaResults) == 1 { - if r.ScaResults[0].IsMultipleRootProject == nil { - return false - } - return *r.ScaResults[0].IsMultipleRootProject - } - return true -} - -func (r *Results) IsScaIssuesFound() bool { - for _, scan := range r.ScaResults { - if scan.HasInformation() { - return true - } - } - return false -} - -func (r *Results) getScaScanResultByTarget(target string) *ScaScanResult { - for _, scan := range r.ScaResults { - if scan.Target == target { - return scan - } - } - return nil -} - -func (r *Results) IsIssuesFound() bool { - if r.IsScaIssuesFound() { - return true - } - if r.ExtendedScanResults.IsIssuesFound() { - return true - } - return false -} - -// Counts the total number of unique findings in the provided results. -// A unique SCA finding is identified by a unique pair of vulnerability's/violation's issueId and component id or by a result returned from one of JAS scans. -func (r *Results) CountScanResultsFindings(includeVulnerabilities, includeViolations bool) (total int) { - summary := formats.ResultsSummary{Scans: GetScanSummaryByTargets(r, includeVulnerabilities, includeViolations)} - if summary.HasViolations() { - return summary.GetTotalViolations() - } - return summary.GetTotalVulnerabilities() -} - -type ScaScanResult struct { - // Could be working directory (audit), file path (binary scan) or build name+number (build scan) - Target string `json:"Target"` - Name string `json:"Name,omitempty"` - Technology techutils.Technology `json:"Technology,omitempty"` - XrayResults []services.ScanResponse `json:"XrayResults,omitempty"` - Descriptors []string `json:"Descriptors,omitempty"` - IsMultipleRootProject *bool `json:"IsMultipleRootProject,omitempty"` -} - -func (s ScaScanResult) HasInformation() bool { - for _, scan := range s.XrayResults { - if len(scan.Vulnerabilities) > 0 || len(scan.Violations) > 0 || len(scan.Licenses) > 0 { - return true - } - } - return false -} - -type ExtendedScanResults struct { - ApplicabilityScanResults []*sarif.Run - SecretsScanResults []*sarif.Run - IacScanResults []*sarif.Run - SastScanResults []*sarif.Run - EntitledForJas bool -} - -func (e *ExtendedScanResults) IsIssuesFound() bool { - return sarifutils.GetResultsLocationCount(e.ApplicabilityScanResults...) > 0 || - sarifutils.GetResultsLocationCount(e.SecretsScanResults...) > 0 || - sarifutils.GetResultsLocationCount(e.IacScanResults...) > 0 || - sarifutils.GetResultsLocationCount(e.SastScanResults...) > 0 -} - -func (e *ExtendedScanResults) GetResultsForTarget(target string) (result *ExtendedScanResults) { - return &ExtendedScanResults{ - ApplicabilityScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.ApplicabilityScanResults...), - SecretsScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.SecretsScanResults...), - IacScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.IacScanResults...), - SastScanResults: sarifutils.GetRunsByWorkingDirectory(target, e.SastScanResults...), - } -} diff --git a/utils/results/common.go b/utils/results/common.go index f8109c0f..d5267a0e 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -1,12 +1,15 @@ package results import ( + "errors" "fmt" "path/filepath" "strconv" "strings" + "github.com/jfrog/gofrog/datastructures" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" @@ -28,8 +31,8 @@ const ( ) var ( - ConvertorResetErr = fmt.Errorf("Reset must be called before parsing new scan results metadata") - ConvertorNewScanErr = fmt.Errorf("ParseNewScanResultsMetadata must be called before starting to parse issues") + ErrConvertorReset = fmt.Errorf("reset must be called before parsing new scan results metadata") + ErrConvertorNewScan = fmt.Errorf("ParseNewTargetResults must be called before starting to parse issues") ) func NewFailBuildError() error { @@ -48,12 +51,13 @@ func CheckIfFailBuild(results []services.ScanResponse) bool { return false } -type PrepareScaVulnerabilityFunc func(vulnerability services.Vulnerability, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error -type PrepareScaViolationFunc func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error -type PrepareLicensesFunc func(license services.License, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error -type PrepareJasFunc func(run *sarif.Run, rule *sarif.ReportingDescriptor, severity severityutils.Severity, result *sarif.Result, location *sarif.Location) error +type ParseScaVulnerabilityFunc func(vulnerability services.Vulnerability, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error +type ParseScaViolationFunc func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error +type ParseLicensesFunc func(license services.License, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error +type ParseJasFunc func(run *sarif.Run, rule *sarif.ReportingDescriptor, severity severityutils.Severity, result *sarif.Result, location *sarif.Location) error -func PrepareJasIssues(target string, runs []*sarif.Run, entitledForJas bool, handler PrepareJasFunc) error { +// PrepareJasIssues allows to iterate over the provided SARIF runs and call the provided handler for each issue to process it. +func PrepareJasIssues(target ScanTarget, runs []*sarif.Run, entitledForJas bool, handler ParseJasFunc) error { if !entitledForJas || handler == nil { return nil } @@ -84,12 +88,13 @@ func PrepareJasIssues(target string, runs []*sarif.Run, entitledForJas bool, han return nil } -func PrepareScaVulnerabilities(target string, vulnerabilities []services.Vulnerability, pretty, entitledForJas bool, applicabilityRuns []*sarif.Run, handler PrepareScaVulnerabilityFunc) error { +// PrepareScaVulnerabilities allows to iterate over the provided vulnerabilities and call the provided handler for each vulnerability to process it. +func PrepareScaVulnerabilities(target ScanTarget, vulnerabilities []services.Vulnerability, pretty, entitledForJas bool, applicabilityRuns []*sarif.Run, handler ParseScaVulnerabilityFunc) error { if handler == nil { return nil } for _, vulnerability := range vulnerabilities { - impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, fixedVersions, directComponents, impactPaths, err := SplitComponents(target, vulnerability.Components) + impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, fixedVersions, directComponents, impactPaths, err := SplitComponents(target.Target, vulnerability.Components) if err != nil { return err } @@ -111,68 +116,88 @@ func PrepareScaVulnerabilities(target string, vulnerabilities []services.Vulnera return nil } -func PrepareScaViolations(target string, violations []services.Violation, pretty, entitledForJas bool, applicabilityRuns []*sarif.Run, securityHandler PrepareScaViolationFunc, licenseHandler PrepareScaViolationFunc, operationalRiskHandler PrepareScaViolationFunc) error { +// PrepareScaViolations allows to iterate over the provided violations and call the provided handler for each violation to process it. +func PrepareScaViolations(target ScanTarget, violations []services.Violation, pretty, entitledForJas bool, applicabilityRuns []*sarif.Run, securityHandler ParseScaViolationFunc, licenseHandler ParseScaViolationFunc, operationalRiskHandler ParseScaViolationFunc) (watches []string, failBuild bool, err error) { + if securityHandler == nil && licenseHandler == nil && operationalRiskHandler == nil { + return + } + watchesSet := datastructures.MakeSet[string]() for _, violation := range violations { - impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, fixedVersions, directComponents, impactPaths, err := SplitComponents(target, violation.Components) - if err != nil { - return err + // Handle duplicates and general attributes + watchesSet.Add(violation.WatchName) + failBuild = failBuild || violation.FailBuild + // Prepare violation information + impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, fixedVersions, directComponents, impactPaths, e := SplitComponents(target.Target, violation.Components) + if e != nil { + err = errors.Join(err, e) + continue } cves, applicabilityStatus := ConvertCvesWithApplicability(violation.Cves, entitledForJas, applicabilityRuns, violation.Components) - severity, err := severityutils.ParseSeverity(violation.Severity, false) - if err != nil { - return err + severity, e := severityutils.ParseSeverity(violation.Severity, false) + if e != nil { + err = errors.Join(err, e) + continue } + // Parse the violation according to its type switch violation.ViolationType { - case formats.ViolationTypeSecurity.String(): + case utils.ViolationTypeSecurity.String(): if securityHandler == nil { + // No handler was provided for security violations continue } for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { - if err := securityHandler( + if e := securityHandler( violation, cves, applicabilityStatus, severity, impactedPackagesNames[compIndex], impactedPackagesVersions[compIndex], impactedPackagesTypes[compIndex], fixedVersions[compIndex], directComponents[compIndex], impactPaths[compIndex], - ); err != nil { - return err + ); e != nil { + err = errors.Join(err, e) + continue } } - case formats.ViolationTypeLicense.String(): + case utils.ViolationTypeLicense.String(): if licenseHandler == nil { + // No handler was provided for license violations continue } for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { - if err := licenseHandler( + if e := licenseHandler( violation, cves, applicabilityStatus, severity, impactedPackagesNames[compIndex], impactedPackagesVersions[compIndex], impactedPackagesTypes[compIndex], fixedVersions[compIndex], directComponents[compIndex], impactPaths[compIndex], - ); err != nil { - return err + ); e != nil { + err = errors.Join(err, e) + continue } } - case formats.ViolationTypeOperationalRisk.String(): + case utils.ViolationTypeOperationalRisk.String(): if operationalRiskHandler == nil { + // No handler was provided for operational risk violations continue } for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { - if err := operationalRiskHandler( + if e := operationalRiskHandler( violation, cves, applicabilityStatus, severity, impactedPackagesNames[compIndex], impactedPackagesVersions[compIndex], impactedPackagesTypes[compIndex], fixedVersions[compIndex], directComponents[compIndex], impactPaths[compIndex], - ); err != nil { - return err + ); e != nil { + err = errors.Join(err, e) + continue } } } } - return nil + watches = watchesSet.ToSlice() + return } -func PrepareLicenses(target string, licenses []services.License, handler PrepareLicensesFunc) error { +// PrepareLicenses allows to iterate over the provided licenses and call the provided handler for each license to process it. +func PrepareLicenses(target ScanTarget, licenses []services.License, handler ParseLicensesFunc) error { if handler == nil { return nil } for _, license := range licenses { - impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, _, directComponents, impactPaths, err := SplitComponents(target, license.Components) + impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, _, directComponents, impactPaths, err := SplitComponents(target.Target, license.Components) if err != nil { return err } @@ -323,7 +348,7 @@ func GetViolatedLicenses(allowedLicenses []string, licenses []services.License) Components: license.Components, IssueId: customLicenseViolationId, WatchName: fmt.Sprintf("jfrog_%s", customLicenseViolationId), - ViolationType: formats.ViolationTypeLicense.String(), + ViolationType: utils.ViolationTypeLicense.String(), }) } } diff --git a/utils/results/conversion/convertor.go b/utils/results/conversion/convertor.go index e969536b..a16c8fc9 100644 --- a/utils/results/conversion/convertor.go +++ b/utils/results/conversion/convertor.go @@ -3,13 +3,13 @@ package conversion import ( "strings" + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/results/conversion/sarifparser" "github.com/jfrog/jfrog-cli-security/utils/results/conversion/simplejsonparser" "github.com/jfrog/jfrog-cli-security/utils/results/conversion/summaryparser" "github.com/jfrog/jfrog-cli-security/utils/results/conversion/tableparser" - "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-client-go/xray/services" "github.com/owenrumney/go-sarif/v2/sarif" ) @@ -19,20 +19,21 @@ type CommandResultsConvertor struct { } type ResultConvertParams struct { - // Control and override converting command results as multi target results - IsMultipleRoots *bool - // Control if the output should include licenses information - IncludeLicenses bool + // If true, a violation context was provided and we expect violation results + HasViolationContext bool // Control if the output should include vulnerabilities information IncludeVulnerabilities bool - // Output will contain only the unique violations determined by the GetUniqueKey function - SimplifiedOutput bool + // Control if the output should include licenses information + IncludeLicenses bool + // Control and override converting command results as multi target results, if nil will be determined by the results.HasMultipleTargets() + IsMultipleRoots *bool // Create local license violations if repo context was not provided and a license is not in this list AllowedLicenses []string - // Convert the results to a pretty format if supported + + // Output will contain only the unique violations determined by the GetUniqueKey function (SimpleJson only) + SimplifiedOutput bool + // Convert the results to a pretty format if supported (Table and Sarif) Pretty bool - // Relevant for Sarif format since Github format does not support results without locations - AllowResultsWithoutLocations bool } func NewCommandResultsConvertor(params ResultConvertParams) *CommandResultsConvertor { @@ -42,17 +43,17 @@ func NewCommandResultsConvertor(params ResultConvertParams) *CommandResultsConve // Parse a stream of results and convert to the desired format type ResultsStreamFormatParser interface { // Reset the convertor to start converting a new command results - Reset(multiScanId, xrayVersion string, entitledForJas, multipleTargets bool) error + Reset(cmdType utils.CommandType, multiScanId, xrayVersion string, entitledForJas, multipleTargets bool) error // Will be called for each scan target (indicating the current is done parsing and starting to parse a new scan) - ParseNewTargetResults(target string, errors ...error) error + ParseNewTargetResults(target results.ScanTarget, errors ...error) error // Parse SCA content to the current scan target - ParseViolations(target string, tech techutils.Technology, violations []services.Violation, applicabilityRuns ...*sarif.Run) error - ParseVulnerabilities(target string, tech techutils.Technology, vulnerabilities []services.Vulnerability, applicabilityRuns ...*sarif.Run) error - ParseLicenses(target string, tech techutils.Technology, licenses []services.License) error + ParseViolations(target results.ScanTarget, scaResponse services.ScanResponse, applicabilityRuns ...*sarif.Run) error + ParseVulnerabilities(target results.ScanTarget, scaResponse services.ScanResponse, applicabilityRuns ...*sarif.Run) error + ParseLicenses(target results.ScanTarget, licenses []services.License) error // Parse JAS content to the current scan target - ParseSecrets(target string, secrets ...*sarif.Run) error - ParseIacs(target string, iacs ...*sarif.Run) error - ParseSast(target string, sast ...*sarif.Run) error + ParseSecrets(target results.ScanTarget, secrets ...*sarif.Run) error + ParseIacs(target results.ScanTarget, iacs ...*sarif.Run) error + ParseSast(target results.ScanTarget, sast ...*sarif.Run) error } func (c *CommandResultsConvertor) ConvertToSimpleJson(cmdResults *results.SecurityCommandResults) (simpleJsonResults formats.SimpleJsonResults, err error) { @@ -71,7 +72,7 @@ func (c *CommandResultsConvertor) ConvertToSimpleJson(cmdResults *results.Securi } func (c *CommandResultsConvertor) ConvertToSarif(cmdResults *results.SecurityCommandResults) (sarifReport *sarif.Report, err error) { - parser := sarifparser.NewCmdResultsSarifConverter(c.Params.Pretty, c.Params.AllowResultsWithoutLocations) + parser := sarifparser.NewCmdResultsSarifConverter(c.Params.Pretty, c.Params.IncludeVulnerabilities, c.Params.HasViolationContext) err = c.parseCommandResults(parser, cmdResults) if err != nil { return @@ -94,8 +95,8 @@ func (c *CommandResultsConvertor) ConvertToTable(cmdResults *results.SecurityCom return } -func (c *CommandResultsConvertor) ConvertToSummary(cmdResults *results.SecurityCommandResults) (summaryResults formats.SummaryResults, err error) { - parser := summaryparser.NewCmdResultsSummaryConverter() +func (c *CommandResultsConvertor) ConvertToSummary(cmdResults *results.SecurityCommandResults) (summaryResults formats.ResultsSummary, err error) { + parser := summaryparser.NewCmdResultsSummaryConverter(c.Params.IncludeVulnerabilities, c.Params.HasViolationContext) err = c.parseCommandResults(parser, cmdResults) if err != nil { return @@ -109,11 +110,11 @@ func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormat if c.Params.IsMultipleRoots != nil { multipleTargets = *c.Params.IsMultipleRoots } - if err = parser.Reset(cmdResults.MultiScanId, cmdResults.XrayVersion, jasEntitled, multipleTargets); err != nil { + if err = parser.Reset(cmdResults.CmdType, cmdResults.MultiScanId, cmdResults.XrayVersion, jasEntitled, multipleTargets); err != nil { return } for _, targetScansResults := range cmdResults.Targets { - if err = parser.ParseNewTargetResults(targetScansResults.Target, targetScansResults.Errors...); err != nil { + if err = parser.ParseNewTargetResults(targetScansResults.ScanTarget, targetScansResults.Errors...); err != nil { return } if targetScansResults.ScaResults != nil { @@ -124,13 +125,13 @@ func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormat if !jasEntitled || targetScansResults.JasResults == nil { continue } - if err = parser.ParseSecrets(targetScansResults.Target, targetScansResults.JasResults.SecretsScanResults...); err != nil { + if err = parser.ParseSecrets(targetScansResults.ScanTarget, targetScansResults.JasResults.SecretsScanResults...); err != nil { return } - if err = parser.ParseIacs(targetScansResults.Target, targetScansResults.JasResults.IacScanResults...); err != nil { + if err = parser.ParseIacs(targetScansResults.ScanTarget, targetScansResults.JasResults.IacScanResults...); err != nil { return } - if err = parser.ParseSast(targetScansResults.Target, targetScansResults.JasResults.SastScanResults...); err != nil { + if err = parser.ParseSast(targetScansResults.ScanTarget, targetScansResults.JasResults.SastScanResults...); err != nil { return } } @@ -138,32 +139,34 @@ func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormat } func (c *CommandResultsConvertor) parseScaResults(parser ResultsStreamFormatParser, targetScansResults *results.TargetResults, jasEntitled bool) (err error) { + if targetScansResults.ScaResults == nil { + return + } for _, scaResults := range targetScansResults.ScaResults.XrayResults { - actualTarget := getScaScanTarget(targetScansResults.ScaResults, targetScansResults.Target) + actualTarget := targetScansResults.ScanTarget.Copy(getScaScanTarget(targetScansResults.ScaResults, targetScansResults.Target)) var applicableRuns []*sarif.Run if jasEntitled && targetScansResults.JasResults != nil { applicableRuns = targetScansResults.JasResults.ApplicabilityScanResults } - if len(scaResults.Vulnerabilities) > 0 { - if err = parser.ParseVulnerabilities(actualTarget, targetScansResults.Technology, scaResults.Vulnerabilities, applicableRuns...); err != nil { + if c.Params.IncludeVulnerabilities { + if err = parser.ParseVulnerabilities(actualTarget, scaResults, applicableRuns...); err != nil { return } } - if len(scaResults.Violations) > 0 { - if err = parser.ParseViolations(actualTarget, targetScansResults.Technology, scaResults.Violations, applicableRuns...); err != nil { + if c.Params.HasViolationContext { + if err = parser.ParseViolations(actualTarget, scaResults, applicableRuns...); err != nil { return } - } else if len(c.Params.AllowedLicenses) > 0 { + } else if len(scaResults.Violations) == 0 && len(c.Params.AllowedLicenses) > 0 { // If no violations were found, check if there are licenses that are not allowed - licViolations := results.GetViolatedLicenses(c.Params.AllowedLicenses, scaResults.Licenses) - if len(licViolations) > 0 { - if err = parser.ParseViolations(actualTarget, targetScansResults.Technology, results.GetViolatedLicenses(c.Params.AllowedLicenses, scaResults.Licenses)); err != nil { + if scaResults.Violations = results.GetViolatedLicenses(c.Params.AllowedLicenses, scaResults.Licenses); len(scaResults.Violations) > 0 { + if err = parser.ParseViolations(actualTarget, scaResults); err != nil { return } } } if c.Params.IncludeLicenses { - if err = parser.ParseLicenses(actualTarget, targetScansResults.Technology, scaResults.Licenses); err != nil { + if err = parser.ParseLicenses(actualTarget, scaResults.Licenses); err != nil { return } } @@ -171,13 +174,15 @@ func (c *CommandResultsConvertor) parseScaResults(parser ResultsStreamFormatPars return } +// Get the best match for the scan target in the sca results func getScaScanTarget(scaResults *results.ScaScanResults, target string) string { if scaResults == nil || len(scaResults.Descriptors) == 0 { - // If target was not provided, use the scan target + // If No Sca scan or no descriptors discovered, use the scan target (build-scan, binary-scan...) // TODO: make sure works for build-scan since its not a file return target } // Get the one that it's directory is the prefix of the target and the shortest + // This is for multi module projects where there are multiple sca results for the same target var bestMatch string for _, descriptor := range scaResults.Descriptors { if strings.HasPrefix(descriptor, target) && (bestMatch == "" || len(descriptor) < len(bestMatch)) { diff --git a/utils/results/conversion/convertor_test.go b/utils/results/conversion/convertor_test.go index e91a1879..08ca7fbb 100644 --- a/utils/results/conversion/convertor_test.go +++ b/utils/results/conversion/convertor_test.go @@ -5,7 +5,9 @@ import ( "path/filepath" "testing" + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-client-go/utils/log" testUtils "github.com/jfrog/jfrog-cli-security/tests/utils" "github.com/jfrog/jfrog-cli-security/utils/results" @@ -16,7 +18,7 @@ import ( ) var ( - testDataDir = filepath.Join("..", "..", "..", "tests", "testdata", "other", "output", "formats") + testDataDir = filepath.Join("..", "..", "..", "tests", "testdata", "output") ) const ( @@ -27,53 +29,63 @@ const ( type conversionFormat string -func getValidationParams() validations.ValidationParams { +func getAuditValidationParams() validations.ValidationParams { return validations.ValidationParams{ ExactResultsMatch: true, - Vulnerabilities: 12, + SecurityViolations: 11, + + Vulnerabilities: 19, Applicable: 1, NotApplicable: 7, NotCovered: 4, Sast: 4, - Secrets: 5, + Secrets: 3, } } func TestConvertResults(t *testing.T) { - inputResults := testUtils.ReadCmdScanResults(t, filepath.Join(testDataDir, "audit_results.json")) + auditInputResults := testUtils.ReadCmdScanResults(t, filepath.Join(testDataDir, "audit", "audit_results.json")) testCases := []struct { contentFormat conversionFormat + inputResults *results.SecurityCommandResults expectedContentPath string }{ { contentFormat: SimpleJson, - expectedContentPath: filepath.Join(testDataDir, "audit_simple_json.json"), + inputResults: auditInputResults, + expectedContentPath: filepath.Join(testDataDir, "audit", "audit_simple_json.json"), }, { contentFormat: Sarif, - expectedContentPath: filepath.Join(testDataDir, "audit_sarif.json"), + inputResults: auditInputResults, + expectedContentPath: filepath.Join(testDataDir, "audit", "audit_sarif.json"), }, { contentFormat: Summary, - expectedContentPath: filepath.Join(testDataDir, "audit_summary.json"), + inputResults: auditInputResults, + expectedContentPath: filepath.Join(testDataDir, "audit", "audit_summary.json"), }, } for _, testCase := range testCases { t.Run(fmt.Sprintf("Convert to %s", testCase.contentFormat), func(t *testing.T) { - validationParams := getValidationParams() - convertor := NewCommandResultsConvertor(ResultConvertParams{}) + validationParams := getAuditValidationParams() + pretty := false + if testCase.contentFormat == Sarif { + pretty = true + } + convertor := NewCommandResultsConvertor(ResultConvertParams{IncludeVulnerabilities: true, HasViolationContext: true, Pretty: pretty}) switch testCase.contentFormat { case SimpleJson: - validateSimpleJsonConversion(t, testUtils.ReadSimpleJsonResults(t, testCase.expectedContentPath), inputResults, convertor, validationParams) + validateSimpleJsonConversion(t, testUtils.ReadSimpleJsonResults(t, testCase.expectedContentPath), testCase.inputResults, convertor, validationParams) case Sarif: - validateSarifConversion(t, testUtils.ReadSarifResults(t, testCase.expectedContentPath), inputResults, convertor, validationParams) + validateSarifConversion(t, testUtils.ReadSarifResults(t, testCase.expectedContentPath), testCase.inputResults, convertor, validationParams) case Summary: - validateSummaryConversion(t, testUtils.ReadSummaryResults(t, testCase.expectedContentPath), inputResults, convertor, validationParams) + validateSummaryConversion(t, testUtils.ReadSummaryResults(t, testCase.expectedContentPath), testCase.inputResults, convertor, validationParams) } }) } @@ -100,10 +112,14 @@ func validateSarifConversion(t *testing.T, expectedResults *sarif.Report, inputR } validationParams.Actual = actualResults + marshAct, err := utils.GetAsJsonString(actualResults, false, true) + assert.NoError(t, err) + log.Output(marshAct) + validations.ValidateCommandSarifOutput(t, validationParams) } -func validateSummaryConversion(t *testing.T, expectedResults formats.SummaryResults, inputResults *results.SecurityCommandResults, convertor *CommandResultsConvertor, validationParams validations.ValidationParams) { +func validateSummaryConversion(t *testing.T, expectedResults formats.ResultsSummary, inputResults *results.SecurityCommandResults, convertor *CommandResultsConvertor, validationParams validations.ValidationParams) { validationParams.Expected = expectedResults actualResults, err := convertor.ConvertToSummary(inputResults) diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index 386383e7..08e04e89 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -2,8 +2,13 @@ package sarifparser import ( "fmt" + "os" + "path/filepath" + "regexp" "strings" + "github.com/owenrumney/go-sarif/v2/sarif" + "github.com/jfrog/gofrog/datastructures" "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" @@ -11,40 +16,61 @@ import ( "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/severityutils" - "github.com/jfrog/jfrog-cli-security/utils/techutils" + + "github.com/jfrog/jfrog-client-go/utils/io/fileutils" + "github.com/jfrog/jfrog-client-go/utils/log" "github.com/jfrog/jfrog-client-go/xray/services" - "github.com/owenrumney/go-sarif/v2/sarif" ) const ( FixedVersionSarifPropertyKey = "fixedVersion" WatchSarifPropertyKey = "watch" - ScaToolName = "JFrog Xray SCA" SastToolName = "USAF" IacToolName = "JFrog Terraform scanner" // #nosec G101 -- Not credentials. SecretsToolName = "JFrog Secrets scanner" ContexualAnalysisToolName = "JFrog Applicability Scanner" + + // TODO: remove above if not used + + CurrentWorkflowNameEnvVar = "GITHUB_WORKFLOW" + CurrentWorkflowRunNumberEnvVar = "GITHUB_RUN_NUMBER" + CurrentWorkflowWorkspaceEnvVar = "GITHUB_WORKSPACE" + + jfrogFingerprintAlgorithmName = "jfrogFingerprintHash" + MissingCveScore = "0" + maxPossibleCve = 10.0 + + // #nosec G101 -- Not credentials. + binarySecretScannerToolName = "JFrog Binary Secrets Scanner" + ScaScannerToolName = "JFrog Xray Scanner" +) + +var ( + GithubBaseWorkflowDir = filepath.Join(".github", "workflows") + dockerJasLocationPathPattern = regexp.MustCompile(`.*[\\/](?P[^\\/]+)[\\/](?P[0-9a-fA-F]+)[\\/](?P.*)`) + dockerScaComponentNamePattern = regexp.MustCompile(`(?P[^__]+)__(?P[0-9a-fA-F]+)\.tar`) ) type CmdResultsSarifConverter struct { - // Add contextual analysis results to the Sarif report - withContextualAnalysis bool // Pretty print the output text for Github Issues support pretty bool + // Include vulnerabilities/violations in the output + includeVulnerabilities bool + hasViolationContext bool // Current stream parse cache information - current *sarif.Report - scaCurrentRun *sarif.Run - currentApplicableRuns *datastructures.Set[*sarif.Run] - + current *sarif.Report + scaCurrentRun *sarif.Run + parsedScaKeys *datastructures.Set[string] // General information on the current command results entitledForJas bool xrayVersion string + currentCmdType utils.CommandType } -func NewCmdResultsSarifConverter(pretty, withContextualAnalysis bool) *CmdResultsSarifConverter { - return &CmdResultsSarifConverter{pretty: pretty, withContextualAnalysis: withContextualAnalysis} +func NewCmdResultsSarifConverter(pretty, includeVulnerabilities, hasViolationContext bool) *CmdResultsSarifConverter { + return &CmdResultsSarifConverter{pretty: pretty, includeVulnerabilities: includeVulnerabilities, hasViolationContext: hasViolationContext} } func (sc *CmdResultsSarifConverter) Get() (*sarif.Report, error) { @@ -53,122 +79,123 @@ func (sc *CmdResultsSarifConverter) Get() (*sarif.Report, error) { return sarifutils.NewReport() } // Flush the current run - if err := sc.ParseNewTargetResults("", nil); err != nil { + if err := sc.ParseNewTargetResults(results.ScanTarget{}, nil); err != nil { return sarifutils.NewReport() } return sc.current, nil } -func (sc *CmdResultsSarifConverter) Reset(_, xrayVersion string, entitledForJas, _ bool) (err error) { +func (sc *CmdResultsSarifConverter) Reset(cmdType utils.CommandType, _, xrayVersion string, entitledForJas, _ bool) (err error) { sc.current, err = sarifutils.NewReport() if err != nil { return } - sc.currentApplicableRuns = datastructures.MakeSet[*sarif.Run]() - sc.scaCurrentRun = nil - + // Reset the current stream general information + sc.currentCmdType = cmdType sc.xrayVersion = xrayVersion sc.entitledForJas = entitledForJas + // Reset the current stream cache information + sc.scaCurrentRun = nil return } -func (sc *CmdResultsSarifConverter) ParseNewTargetResults(target string, errors ...error) (err error) { +func (sc *CmdResultsSarifConverter) ParseNewTargetResults(target results.ScanTarget, errors ...error) (err error) { if sc.current == nil { - return results.ConvertorResetErr + return results.ErrConvertorReset } if sc.scaCurrentRun != nil { - sc.current.Runs = append(sc.current.Runs, sc.scaCurrentRun) - if sc.withContextualAnalysis { - sc.current.Runs = append(sc.current.Runs, sc.currentApplicableRuns.ToSlice()...) - } + // Flush the current run + sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.ScaScan, target, sc.scaCurrentRun)...) + } + if sc.hasViolationContext || sc.includeVulnerabilities { + // Create Sca Run if requested to parse all vulnerabilities/violations to it + sc.scaCurrentRun = sc.createScaRun(target, len(errors)) + sc.parsedScaKeys = datastructures.MakeSet[string]() } - sc.scaCurrentRun = sarif.NewRunWithInformationURI(ScaToolName, utils.BaseDocumentationURL+"sca") - sc.scaCurrentRun.Tool.Driver.Version = &sc.xrayVersion - // Add target as working directory in the run invocation - sc.scaCurrentRun.Invocations = append(sc.scaCurrentRun.Invocations, sarif.NewInvocation(). - WithWorkingDirectory(sarif.NewSimpleArtifactLocation(target)). - WithExecutionSuccess(len(errors) == 0), - ) return } -func (sc *CmdResultsSarifConverter) ParseViolations(target string, tech techutils.Technology, violations []services.Violation, applicabilityRuns ...*sarif.Run) (err error) { +func (sc *CmdResultsSarifConverter) createScaRun(target results.ScanTarget, errorCount int) *sarif.Run { + run := sarif.NewRunWithInformationURI(ScaScannerToolName, utils.BaseDocumentationURL+"sca") + run.Tool.Driver.Version = &sc.xrayVersion + run.Invocations = append(run.Invocations, sarif.NewInvocation(). + WithWorkingDirectory(sarif.NewSimpleArtifactLocation(target.Target)). + WithExecutionSuccess(errorCount == 0), + ) + return run +} + +// validateBeforeParse checks if the parser is initialized to parse results (checks if Reset and at least one ParseNewTargetResults was called before) +func (sc *CmdResultsSarifConverter) validateBeforeParse() (err error) { if sc.current == nil { - return results.ConvertorResetErr + return results.ErrConvertorReset } - if sc.scaCurrentRun == nil { - return results.ConvertorNewScanErr + if (sc.hasViolationContext || sc.includeVulnerabilities) && sc.scaCurrentRun == nil { + return results.ErrConvertorNewScan } - sarifResults, sarifRules, err := PrepareSarifScaViolations(target, sc.scaCurrentRun, sc.pretty, sc.entitledForJas, violations, applicabilityRuns...) - if err != nil || len(sarifRules) == 0 || len(sarifResults) == 0 { + return +} + +func (sc *CmdResultsSarifConverter) ParseViolations(target results.ScanTarget, scanResponse services.ScanResponse, applicabilityRuns ...*sarif.Run) (err error) { + if err = sc.validateBeforeParse(); err != nil || sc.scaCurrentRun == nil { return } - sc.addScaResultsToCurrentRun(sarifRules, sarifResults...) - if !sc.entitledForJas { + // Parse violations + sarifResults, sarifRules, err := PrepareSarifScaViolations(sc.currentCmdType, target, sc.scaCurrentRun, scanResponse.Violations, sc.pretty, sc.entitledForJas, applicabilityRuns...) + if err != nil || len(sarifRules) == 0 || len(sarifResults) == 0 { return } - for _, run := range applicabilityRuns { - sc.currentApplicableRuns.Add(run) - } + sc.addScaResultsToCurrentRun(sarifRules, sarifResults...) return } -func (sc *CmdResultsSarifConverter) ParseVulnerabilities(target string, tech techutils.Technology, vulnerabilities []services.Vulnerability, applicabilityRuns ...*sarif.Run) (err error) { - if sc.current == nil { - return results.ConvertorResetErr - } - if sc.scaCurrentRun == nil { - return results.ConvertorNewScanErr +func (sc *CmdResultsSarifConverter) ParseVulnerabilities(target results.ScanTarget, scanResponse services.ScanResponse, applicabilityRuns ...*sarif.Run) (err error) { + if err = sc.validateBeforeParse(); err != nil || sc.scaCurrentRun == nil { + return } - sarifResults, sarifRules, err := PrepareSarifScaVulnerabilities(target, vulnerabilities, sc.pretty, sc.entitledForJas, applicabilityRuns...) + sarifResults, sarifRules, err := PrepareSarifScaVulnerabilities(sc.currentCmdType, target, scanResponse.Vulnerabilities, sc.pretty, sc.entitledForJas, applicabilityRuns...) if err != nil || len(sarifRules) == 0 || len(sarifResults) == 0 { return } sc.addScaResultsToCurrentRun(sarifRules, sarifResults...) - if !sc.entitledForJas { - return - } - for _, run := range applicabilityRuns { - sc.currentApplicableRuns.Add(run) - } return } -func (sc *CmdResultsSarifConverter) ParseLicenses(target string, tech techutils.Technology, licenses []services.License) (err error) { +func (sc *CmdResultsSarifConverter) ParseLicenses(target results.ScanTarget, licenses []services.License) (err error) { // Not supported in Sarif format return } -func (sc *CmdResultsSarifConverter) ParseSecrets(_ string, secrets ...*sarif.Run) (err error) { +func (sc *CmdResultsSarifConverter) ParseSecrets(target results.ScanTarget, secrets ...*sarif.Run) (err error) { if !sc.entitledForJas { return } if sc.current == nil { - return results.ConvertorResetErr + return results.ErrConvertorReset } - sc.current.Runs = append(sc.current.Runs, secrets...) + sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.SecretsScan, target, secrets...)...) return } -func (sc *CmdResultsSarifConverter) ParseIacs(_ string, iacs ...*sarif.Run) (err error) { +func (sc *CmdResultsSarifConverter) ParseIacs(target results.ScanTarget, iacs ...*sarif.Run) (err error) { if !sc.entitledForJas { return } if sc.current == nil { - return results.ConvertorResetErr + return results.ErrConvertorReset } - sc.current.Runs = append(sc.current.Runs, iacs...) + sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.IacScan, target, iacs...)...) return } -func (sc *CmdResultsSarifConverter) ParseSast(_ string, sast ...*sarif.Run) (err error) { +func (sc *CmdResultsSarifConverter) ParseSast(target results.ScanTarget, sast ...*sarif.Run) (err error) { if !sc.entitledForJas { return } if sc.current == nil { - return results.ConvertorResetErr + return results.ErrConvertorReset } - sc.current.Runs = append(sc.current.Runs, sast...) + sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.SastScan, target, sast...)...) return } @@ -182,24 +209,24 @@ func (sc *CmdResultsSarifConverter) addScaResultsToCurrentRun(rules map[string]* } } -func PrepareSarifScaViolations(target string, run *sarif.Run, pretty, entitledForJas bool, violations []services.Violation, applicabilityRuns ...*sarif.Run) ([]*sarif.Result, map[string]*sarif.ReportingDescriptor, error) { +func PrepareSarifScaViolations(cmdType utils.CommandType, target results.ScanTarget, run *sarif.Run, violations []services.Violation, pretty, entitledForJas bool, applicabilityRuns ...*sarif.Run) ([]*sarif.Result, map[string]*sarif.ReportingDescriptor, error) { sarifResults := []*sarif.Result{} rules := map[string]*sarif.ReportingDescriptor{} - err := results.PrepareScaViolations( + _, _, err := results.PrepareScaViolations( target, violations, pretty, entitledForJas, applicabilityRuns, - addSarifScaSecurityViolation(&sarifResults, &rules), - addSarifScaLicenseViolation(&sarifResults, &rules), + addSarifScaSecurityViolation(cmdType, &sarifResults, &rules), + addSarifScaLicenseViolation(cmdType, &sarifResults, &rules), // Operational risks violations are not supported in Sarif format nil, ) return sarifResults, rules, err } -func PrepareSarifScaVulnerabilities(target string, vulnerabilities []services.Vulnerability, pretty, entitledForJas bool, applicabilityRuns ...*sarif.Run) ([]*sarif.Result, map[string]*sarif.ReportingDescriptor, error) { +func PrepareSarifScaVulnerabilities(cmdType utils.CommandType, target results.ScanTarget, vulnerabilities []services.Vulnerability, pretty, entitledForJas bool, applicabilityRuns ...*sarif.Run) ([]*sarif.Result, map[string]*sarif.ReportingDescriptor, error) { sarifResults := []*sarif.Result{} rules := map[string]*sarif.ReportingDescriptor{} err := results.PrepareScaVulnerabilities( @@ -208,12 +235,12 @@ func PrepareSarifScaVulnerabilities(target string, vulnerabilities []services.Vu pretty, entitledForJas, applicabilityRuns, - addSarifScaVulnerability(&sarifResults, &rules), + addSarifScaVulnerability(cmdType, &sarifResults, &rules), ) return sarifResults, rules, err } -func addSarifScaVulnerability(sarifResults *[]*sarif.Result, rules *map[string]*sarif.ReportingDescriptor) results.PrepareScaVulnerabilityFunc { +func addSarifScaVulnerability(cmdType utils.CommandType, sarifResults *[]*sarif.Result, rules *map[string]*sarif.ReportingDescriptor) results.ParseScaVulnerabilityFunc { return func(vulnerability services.Vulnerability, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersions []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { maxCveScore, err := results.FindMaxCVEScore(severity, applicabilityStatus, cves) if err != nil { @@ -223,7 +250,7 @@ func addSarifScaVulnerability(sarifResults *[]*sarif.Result, rules *map[string]* if err != nil { return err } - currentResults, currentRule := parseScaToSarifFormat(vulnerability.IssueId, vulnerability.Summary, markdownDescription, maxCveScore, getScaIssueSarifHeadline, cves, severity, applicabilityStatus, impactedPackagesName, impactedPackagesVersion, fixedVersions, directComponents) + currentResults, currentRule := parseScaToSarifFormat(cmdType, vulnerability.IssueId, vulnerability.Summary, markdownDescription, maxCveScore, getScaIssueSarifHeadline, cves, severity, applicabilityStatus, impactedPackagesName, impactedPackagesVersion, fixedVersions, directComponents) cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, results.GetIssueIdentifier(cves, vulnerability.IssueId, "_")) if _, ok := (*rules)[cveImpactedComponentRuleId]; !ok { // New Rule @@ -234,7 +261,7 @@ func addSarifScaVulnerability(sarifResults *[]*sarif.Result, rules *map[string]* } } -func addSarifScaSecurityViolation(sarifResults *[]*sarif.Result, rules *map[string]*sarif.ReportingDescriptor) results.PrepareScaViolationFunc { +func addSarifScaSecurityViolation(cmdType utils.CommandType, sarifResults *[]*sarif.Result, rules *map[string]*sarif.ReportingDescriptor) results.ParseScaViolationFunc { return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersions []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { maxCveScore, err := results.FindMaxCVEScore(severity, applicabilityStatus, cves) if err != nil { @@ -244,7 +271,7 @@ func addSarifScaSecurityViolation(sarifResults *[]*sarif.Result, rules *map[stri if err != nil { return err } - currentResults, currentRule := parseScaToSarifFormat(violation.IssueId, violation.Summary, markdownDescription, maxCveScore, getScaIssueSarifHeadline, cves, severity, applicabilityStatus, impactedPackagesName, impactedPackagesVersion, fixedVersions, directComponents) + currentResults, currentRule := parseScaToSarifFormat(cmdType, violation.IssueId, violation.Summary, markdownDescription, maxCveScore, getScaIssueSarifHeadline, cves, severity, applicabilityStatus, impactedPackagesName, impactedPackagesVersion, fixedVersions, directComponents, violation.WatchName) cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, results.GetIssueIdentifier(cves, violation.IssueId, "_")) if _, ok := (*rules)[cveImpactedComponentRuleId]; !ok { // New Rule @@ -255,7 +282,7 @@ func addSarifScaSecurityViolation(sarifResults *[]*sarif.Result, rules *map[stri } } -func addSarifScaLicenseViolation(sarifResults *[]*sarif.Result, rules *map[string]*sarif.ReportingDescriptor) results.PrepareScaViolationFunc { +func addSarifScaLicenseViolation(cmdType utils.CommandType, sarifResults *[]*sarif.Result, rules *map[string]*sarif.ReportingDescriptor) results.ParseScaViolationFunc { return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersions []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { maxCveScore, err := results.FindMaxCVEScore(severity, applicabilityStatus, cves) if err != nil { @@ -265,20 +292,7 @@ func addSarifScaLicenseViolation(sarifResults *[]*sarif.Result, rules *map[strin if err != nil { return err } - currentResults, currentRule := parseScaToSarifFormat( - violation.LicenseKey, - getLicenseViolationSummary(impactedPackagesName, impactedPackagesVersion, violation.LicenseKey), - markdownDescription, - maxCveScore, - getXrayLicenseSarifHeadline, - cves, - severity, - applicabilityStatus, - impactedPackagesName, - impactedPackagesVersion, - fixedVersions, - directComponents, - ) + currentResults, currentRule := parseScaToSarifFormat(cmdType, violation.LicenseKey, getLicenseViolationSummary(impactedPackagesName, impactedPackagesVersion, violation.LicenseKey), markdownDescription, maxCveScore, getXrayLicenseSarifHeadline, cves, severity, applicabilityStatus, impactedPackagesName, impactedPackagesVersion, fixedVersions, directComponents) cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, results.GetIssueIdentifier(cves, violation.LicenseKey, "_")) if _, ok := (*rules)[cveImpactedComponentRuleId]; !ok { // New Rule @@ -289,7 +303,7 @@ func addSarifScaLicenseViolation(sarifResults *[]*sarif.Result, rules *map[strin } } -func parseScaToSarifFormat(xrayId, summary, markdownDescription, cveScore string, generateTitleFunc func(depName string, version string, issueId string) string, cves []formats.CveRow, severity severityutils.Severity, applicabilityStatus jasutils.ApplicabilityStatus, impactedPackagesName, impactedPackagesVersion string, fixedVersions []string, directComponents []formats.ComponentRow, watches ...string) (sarifResults []*sarif.Result, rule *sarif.ReportingDescriptor) { +func parseScaToSarifFormat(cmdType utils.CommandType, xrayId, summary, markdownDescription, cveScore string, generateTitleFunc func(depName string, version string, issueId string) string, cves []formats.CveRow, severity severityutils.Severity, applicabilityStatus jasutils.ApplicabilityStatus, impactedPackagesName, impactedPackagesVersion string, fixedVersions []string, directComponents []formats.ComponentRow, watches ...string) (sarifResults []*sarif.Result, rule *sarif.ReportingDescriptor) { // General information issueId := results.GetIssueIdentifier(cves, xrayId, "_") cveImpactedComponentRuleId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, issueId) @@ -318,7 +332,7 @@ func parseScaToSarifFormat(xrayId, summary, markdownDescription, cveScore string resultsProperties.Add(FixedVersionSarifPropertyKey, getFixedVersionString(fixedVersions)) issueResult.AttachPropertyBag(resultsProperties) // Add location - issueLocation := getComponentSarifLocation(directDependency) + issueLocation := getComponentSarifLocation(cmdType, directDependency) if issueLocation != nil { issueResult.AddLocation(issueLocation) } @@ -336,7 +350,7 @@ func getScaIssueSarifRule(ruleId, ruleDescription, maxCveScore, summary, markdow WithProperties(cveRuleProperties.Properties) } -func getComponentSarifLocation(component formats.ComponentRow) *sarif.Location { +func getComponentSarifLocation(cmtType utils.CommandType, component formats.ComponentRow) *sarif.Location { filePath := "" if component.Location != nil { filePath = component.Location.File @@ -345,15 +359,20 @@ func getComponentSarifLocation(component formats.ComponentRow) *sarif.Location { // For tech that we don't support fetching the package descriptor related to the component filePath = "Package-Descriptor" } - // TODO: Add to location the following - // https://sarifweb.azurewebsites.net/Validation - // "logicalLocations": [ - // { - // "fullyQualifiedName": "pkg:maven/org.xerial.snappy/snappy-java@1.1.10.1" - // } - // ] + var logicalLocations []*sarif.LogicalLocation + if cmtType == utils.DockerImage { + // Docker image - extract layer hash from component name + algorithm, layer := getLayerContentFromComponentId(component.Name) + if layer != "" { + logicalLocation := sarifutils.NewLogicalLocation(layer, "layer") + if algorithm != "" { + logicalLocation.Properties = map[string]interface{}{"algorithm": algorithm} + } + logicalLocations = append(logicalLocations, logicalLocation) + } + } return sarif.NewLocation(). - WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://" + filePath))) + WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://" + filePath))).WithLogicalLocations(logicalLocations) } func getScaIssueMarkdownDescription(directDependencies []formats.ComponentRow, cveScore string, applicableStatus jasutils.ApplicabilityStatus, fixedVersions []string) (string, error) { @@ -406,3 +425,314 @@ func getScaLicenseViolationMarkdown(depName, version, key string, directDependen } return fmt.Sprintf("%s
Direct dependencies:
%s", getLicenseViolationSummary(depName, version, key), formattedDirectDependencies), nil } + +func patchRunsToPassIngestionRules(cmdType utils.CommandType, subScanType utils.SubScanType, target results.ScanTarget, runs ...*sarif.Run) []*sarif.Run { + // Since we run in temp directories files should be relative + // Patch by converting the file paths to relative paths according to the invocations + convertPaths(cmdType, subScanType, runs...) + for _, run := range runs { + if cmdType.IsTargetBinary() && subScanType == utils.SecretsScan { + // Patch the tool name in case of binary scan + sarifutils.SetRunToolName(binarySecretScannerToolName, run) + } + run.Tool.Driver.Rules = patchRules(cmdType, subScanType, run.Tool.Driver.Rules...) + run.Results = patchResults(cmdType, subScanType, target, run, run.Results...) + } + return runs +} + +func convertPaths(commandType utils.CommandType, subScanType utils.SubScanType, runs ...*sarif.Run) { + // Convert base on invocation for source code + sarifutils.ConvertRunsPathsToRelative(runs...) + if !(commandType == utils.DockerImage && subScanType == utils.SecretsScan) { + return + } + for _, run := range runs { + for _, result := range run.Results { + // For Docker secret scan, patch the logical location if not exists + patchDockerSecretLocations(result) + } + } +} + +// Patch the URI to be the file path from sha// +// Extract the layer from the location URI, adds it as a logical location kind "layer" +func patchDockerSecretLocations(result *sarif.Result) { + for _, location := range result.Locations { + algorithm, layerHash, relativePath := getLayerContentFromPath(sarifutils.GetLocationFileName(location)) + if layerHash != "" { + // Set Logical location kind "layer" with the layer hash + logicalLocation := sarifutils.NewLogicalLocation(layerHash, "layer") + if algorithm != "" { + logicalLocation.Properties = sarif.Properties(map[string]interface{}{"algorithm": algorithm}) + } + location.LogicalLocations = append(location.LogicalLocations, logicalLocation) + } + if relativePath != "" { + sarifutils.SetLocationFileName(location, relativePath) + } + } +} + +func patchRules(commandType utils.CommandType, subScanType utils.SubScanType, rules ...*sarif.ReportingDescriptor) (patched []*sarif.ReportingDescriptor) { + patched = []*sarif.ReportingDescriptor{} + for _, rule := range rules { + // Github code scanning ingestion rules rejects rules without help content. + // Patch by transferring the full description to the help field. + if rule.Help == nil && rule.FullDescription != nil { + rule.Help = rule.FullDescription + } + // SARIF1001 - if both 'id' and 'name' are present, they must be different. If they are identical, the tool must omit the 'name' property. + if rule.Name != nil && rule.ID == *rule.Name { + rule.Name = nil + } + if commandType.IsTargetBinary() && subScanType == utils.SecretsScan { + // Patch the rule name in case of binary scan + sarifutils.SetRuleShortDescriptionText(fmt.Sprintf("[Secret in Binary found] %s", sarifutils.GetRuleShortDescriptionText(rule)), rule) + } + patched = append(patched, rule) + } + return +} + +func patchResults(commandType utils.CommandType, subScanType utils.SubScanType, target results.ScanTarget, run *sarif.Run, results ...*sarif.Result) (patched []*sarif.Result) { + patched = []*sarif.Result{} + for _, result := range results { + if len(result.Locations) == 0 { + // Github code scanning ingestion rules rejects results without locations. + // Patch by removing results without locations. + log.Debug(fmt.Sprintf("[%s] Removing result [ruleId=%s] without locations: %s", subScanType.String(), sarifutils.GetResultRuleId(result), sarifutils.GetResultMsgText(result))) + continue + } + if commandType.IsTargetBinary() { + var markdown string + if subScanType == utils.SecretsScan { + markdown = getSecretInBinaryMarkdownMsg(commandType, target, result) + } else { + markdown = getScaInBinaryMarkdownMsg(commandType, target, result) + } + sarifutils.SetResultMsgMarkdown(markdown, result) + // For Binary scans, override the physical location if applicable (after data already used for markdown) + convertBinaryPhysicalLocations(commandType, run, result) + // Calculate the fingerprints if not exists + if !sarifutils.IsFingerprintsExists(result) { + if err := calculateResultFingerprints(commandType, run, result); err != nil { + log.Warn(fmt.Sprintf("Failed to calculate the fingerprint for result [ruleId=%s]: %s", sarifutils.GetResultRuleId(result), err.Error())) + } + } + } + patched = append(patched, result) + } + return patched +} + +func convertBinaryPhysicalLocations(commandType utils.CommandType, run *sarif.Run, result *sarif.Result) { + if patchedLocation := getPatchedBinaryLocation(commandType, run); patchedLocation != "" { + for _, location := range result.Locations { + // Patch the location - Reset the uri and region + location.PhysicalLocation = sarifutils.NewPhysicalLocation(patchedLocation) + } + } +} + +func getPatchedBinaryLocation(commandType utils.CommandType, run *sarif.Run) (patchedLocation string) { + if commandType == utils.DockerImage { + if patchedLocation = getDockerfileLocationIfExists(run); patchedLocation != "" { + return + } + } + return getWorkflowFileLocationIfExists() +} + +func getDockerfileLocationIfExists(run *sarif.Run) string { + potentialLocations := []string{filepath.Clean("Dockerfile"), sarifutils.GetFullLocationFileName("Dockerfile", run.Invocations)} + for _, location := range potentialLocations { + if exists, err := fileutils.IsFileExists(location, false); err == nil && exists { + return location + } + } + if workspace := os.Getenv(CurrentWorkflowWorkspaceEnvVar); workspace != "" { + if exists, err := fileutils.IsFileExists(filepath.Join(workspace, "Dockerfile"), false); err == nil && exists { + return filepath.Join(workspace, "Dockerfile") + } + } + return "" +} + +func getGithubWorkflowsDirIfExists() string { + if exists, err := fileutils.IsDirExists(GithubBaseWorkflowDir, false); err == nil && exists { + return GithubBaseWorkflowDir + } + if workspace := os.Getenv(CurrentWorkflowWorkspaceEnvVar); workspace != "" { + if exists, err := fileutils.IsDirExists(filepath.Join(workspace, GithubBaseWorkflowDir), false); err == nil && exists { + return filepath.Join(workspace, GithubBaseWorkflowDir) + } + } + return "" +} + +func getWorkflowFileLocationIfExists() (location string) { + workflowName := os.Getenv(CurrentWorkflowNameEnvVar) + if workflowName == "" { + return + } + workflowsDir := getGithubWorkflowsDirIfExists() + if workflowsDir == "" { + return + } + currentWd, err := os.Getwd() + if err != nil { + log.Warn(fmt.Sprintf("Failed to get the current working directory to get workflow file location: %s", err.Error())) + return + } + // Check if exists in the .github/workflows directory as file name or in the content, return the file path or empty string + if files, err := fileutils.ListFiles(workflowsDir, false); err == nil && len(files) > 0 { + for _, file := range files { + if strings.Contains(file, workflowName) { + return strings.TrimPrefix(file, currentWd) + } + } + for _, file := range files { + if content, err := fileutils.ReadFile(file); err == nil && strings.Contains(string(content), workflowName) { + return strings.TrimPrefix(file, currentWd) + } + } + } + return +} + +func getSecretInBinaryMarkdownMsg(commandType utils.CommandType, target results.ScanTarget, result *sarif.Result) string { + if !commandType.IsTargetBinary() { + return "" + } + content := "🔒 Found Secrets in Binary" + if commandType == utils.DockerImage { + content += " docker" + } + content += " scanning:" + return content + getBaseBinaryDescriptionMarkdown(commandType, target, utils.SecretsScan, result) +} + +func getScaInBinaryMarkdownMsg(commandType utils.CommandType, target results.ScanTarget, result *sarif.Result) string { + return sarifutils.GetResultMsgText(result) + getBaseBinaryDescriptionMarkdown(commandType, target, utils.ScaScan, result) +} + +func getBaseBinaryDescriptionMarkdown(commandType utils.CommandType, target results.ScanTarget, subScanType utils.SubScanType, result *sarif.Result) (content string) { + // If in github action, add the workflow name and run number + if workflowLocation := getWorkflowFileLocationIfExists(); workflowLocation != "" { + content += fmt.Sprintf("\nGithub Actions Workflow: %s", workflowLocation) + } + if os.Getenv(CurrentWorkflowRunNumberEnvVar) != "" { + content += fmt.Sprintf("\nRun: %s", os.Getenv(CurrentWorkflowRunNumberEnvVar)) + } + // If is docker image, add the image tag + if commandType == utils.DockerImage { + if imageTag := getDockerImageTag(commandType, target); imageTag != "" { + content += fmt.Sprintf("\nImage: %s", imageTag) + } + } + var location *sarif.Location + if len(result.Locations) > 0 { + location = result.Locations[0] + } + return content + getBinaryLocationMarkdownString(commandType, subScanType, location) +} + +func getDockerImageTag(commandType utils.CommandType, target results.ScanTarget) string { + if commandType != utils.DockerImage { + return "" + } + if target.Name != "" { + return target.Name + } + return filepath.Base(target.Target) +} + +// If command is docker prepare the markdown string for the location: +// * Layer: +// * Filepath: +// * Evidence: +func getBinaryLocationMarkdownString(commandType utils.CommandType, subScanType utils.SubScanType, location *sarif.Location) (content string) { + if location == nil { + return "" + } + if commandType == utils.DockerImage { + if layer, algorithm := getDockerLayer(location); layer != "" { + if algorithm != "" { + content += fmt.Sprintf("\nLayer (%s): %s", algorithm, layer) + } else { + content += fmt.Sprintf("\nLayer: %s", layer) + } + } + } + if subScanType != utils.SecretsScan { + return + } + if locationFilePath := sarifutils.GetLocationFileName(location); locationFilePath != "" { + content += fmt.Sprintf("\nFilepath: %s", locationFilePath) + } + if snippet := sarifutils.GetLocationSnippet(location); snippet != "" { + content += fmt.Sprintf("\nEvidence: %s", snippet) + } + return +} + +func getDockerLayer(location *sarif.Location) (layer, algorithm string) { + // If location has logical location with kind "layer" return it + if logicalLocation := sarifutils.GetLogicalLocation("layer", location); logicalLocation != nil && logicalLocation.Name != nil { + layer = *logicalLocation.Name + if algorithmValue, ok := logicalLocation.Properties["algorithm"].(string); ok { + algorithm = algorithmValue + } + return + } + return +} + +// Match: +// Extract algorithm, hash and relative path +func getLayerContentFromPath(content string) (algorithm string, layerHash string, relativePath string) { + matches := dockerJasLocationPathPattern.FindStringSubmatch(content) + if len(matches) == 0 { + return + } + algorithm = matches[dockerJasLocationPathPattern.SubexpIndex("algorithm")] + layerHash = matches[dockerJasLocationPathPattern.SubexpIndex("hash")] + relativePath = matches[dockerJasLocationPathPattern.SubexpIndex("relativePath")] + return +} + +// Match: __.tar +// Extract algorithm and hash +func getLayerContentFromComponentId(componentId string) (algorithm string, layerHash string) { + matches := dockerScaComponentNamePattern.FindStringSubmatch(componentId) + if len(matches) == 0 { + return + } + algorithm = matches[dockerScaComponentNamePattern.SubexpIndex("algorithm")] + layerHash = matches[dockerScaComponentNamePattern.SubexpIndex("hash")] + return +} + +// According to the SARIF specification: +// To determine whether a result from a subsequent run is logically the same as a result from the baseline, +// there must be a way to use information contained in the result to construct a stable identifier for the result. We refer to this identifier as a fingerprint. +// A result management system SHOULD construct a fingerprint by using information contained in the SARIF file such as: +// The name of the tool that produced the result, the rule id, the file system path to the analysis target... +func calculateResultFingerprints(resultType utils.CommandType, run *sarif.Run, result *sarif.Result) error { + if !resultType.IsTargetBinary() { + return nil + } + ids := []string{sarifutils.GetRunToolName(run), sarifutils.GetResultRuleId(result)} + for _, location := range sarifutils.GetResultFileLocations(result) { + ids = append(ids, strings.ReplaceAll(location, string(filepath.Separator), "/")) + } + ids = append(ids, sarifutils.GetResultLocationSnippets(result)...) + // Calculate the hash value and set the fingerprint to the result + hashValue, err := utils.Md5Hash(ids...) + if err != nil { + return err + } + sarifutils.SetResultFingerprint(jfrogFingerprintAlgorithmName, hashValue, result) + return nil +} diff --git a/utils/results/conversion/sarifparser/sarifparser_test.go b/utils/results/conversion/sarifparser/sarifparser_test.go index 0b450dca..2613954e 100644 --- a/utils/results/conversion/sarifparser/sarifparser_test.go +++ b/utils/results/conversion/sarifparser/sarifparser_test.go @@ -2,11 +2,19 @@ package sarifparser import ( "fmt" + "os" "path/filepath" "testing" + "github.com/jfrog/build-info-go/tests" + "github.com/jfrog/jfrog-client-go/utils/io/fileutils" + clientTests "github.com/jfrog/jfrog-client-go/utils/tests" + + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/owenrumney/go-sarif/v2/sarif" "github.com/stretchr/testify/assert" ) @@ -14,6 +22,7 @@ import ( func TestGetComponentSarifLocation(t *testing.T) { testCases := []struct { name string + cmdType utils.CommandType component formats.ComponentRow expectedOutput *sarif.Location }{ @@ -38,11 +47,19 @@ func TestGetComponentSarifLocation(t *testing.T) { WithArtifactLocation(sarif.NewArtifactLocation().WithUri(fmt.Sprintf("file://%s", filepath.Join("dir", "file.txt")))), ), }, + { + name: "Component with location and logical location", + cmdType: utils.DockerImage, + component: formats.ComponentRow{Name: "sha256__3a8bca98bcad879bca98b9acd.tar"}, + expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation(). + WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://Package-Descriptor")), + ).WithLogicalLocations([]*sarif.LogicalLocation{sarifutils.CreateLogicalLocationWithProperty("3a8bca98bcad879bca98b9acd", "layer", "algorithm", "sha256")}), + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, tc.expectedOutput, getComponentSarifLocation(tc.component)) + assert.Equal(t, tc.expectedOutput, getComponentSarifLocation(tc.cmdType, tc.component)) }) } } @@ -204,3 +221,280 @@ func TestGetScaLicenseViolationMarkdown(t *testing.T) { }) } } + +func TestGetLayerContentFromComponentId(t *testing.T) { + testCases := []struct { + name string + path string + expectedAlgorithm string + expectedLayerHash string + }{ + { + name: "Valid path", + path: "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", + expectedAlgorithm: "sha256", + expectedLayerHash: "cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e", + }, + { + name: "Invalid path - not hex", + path: "sha256__NOT_HEX.tar", + }, + { + name: "Invalid path - no algorithm", + path: "_cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", + }, + { + name: "Invalid path - no suffix", + path: "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e", + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + algorithm, layerHash := getLayerContentFromComponentId(tc.path) + assert.Equal(t, tc.expectedAlgorithm, algorithm) + assert.Equal(t, tc.expectedLayerHash, layerHash) + }) + } +} + +func preparePatchTestEnv(t *testing.T) (string, string, func()) { + currentWd, err := os.Getwd() + assert.NoError(t, err) + wd, cleanUpTempDir := tests.CreateTempDirWithCallbackAndAssert(t) + cleanUpWd := clientTests.ChangeDirWithCallback(t, currentWd, wd) + dockerfileDir := filepath.Join(wd, "DockerfileDir") + err = fileutils.CreateDirIfNotExist(dockerfileDir) + // Prepare env content + assert.NoError(t, err) + createDummyDockerfile(t, dockerfileDir) + createDummyGithubWorkflow(t, dockerfileDir) + createDummyGithubWorkflow(t, wd) + return wd, dockerfileDir, func() { + cleanUpWd() + cleanUpTempDir() + } +} + +func createDummyGithubWorkflow(t *testing.T, baseDir string) { + assert.NoError(t, fileutils.CreateDirIfNotExist(filepath.Join(baseDir, GithubBaseWorkflowDir))) + assert.NoError(t, os.WriteFile(filepath.Join(baseDir, GithubBaseWorkflowDir, "workflowFile.yml"), []byte("workflow name"), 0644)) +} + +func createDummyDockerfile(t *testing.T, baseDir string) { + assert.NoError(t, os.WriteFile(filepath.Join(baseDir, "Dockerfile"), []byte("Dockerfile data"), 0644)) +} + +func TestPatchRunsToPassIngestionRules(t *testing.T) { + wd, dockerfileDir, cleanUp := preparePatchTestEnv(t) + defer cleanUp() + + testCases := []struct { + name string + target results.ScanTarget + cmdType utils.CommandType + subScan utils.SubScanType + withEnvVars bool + withDockerfile bool + input []*sarif.Run + expectedResults []*sarif.Run + }{ + { + name: "No runs", + target: results.ScanTarget{Name: "dockerImage:imageVersion"}, + cmdType: utils.DockerImage, + subScan: utils.SecretsScan, + input: []*sarif.Run{}, + expectedResults: []*sarif.Run{}, + }, + { + name: "Build scan - SCA", + target: results.ScanTarget{Name: "buildName (buildNumber)"}, + cmdType: utils.Build, + subScan: utils.ScaScan, + input: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultsInWd(wd, sarifutils.CreateDummyResultInPath(fmt.Sprintf("file://%s", filepath.Join(wd, "dir", "file")))), + }, + expectedResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultsInWd(wd, sarifutils.CreateDummyResultInPath(filepath.Join("dir", "file"))), + }, + }, + { + name: "Docker image scan - SCA", + target: results.ScanTarget{Name: "dockerImage:imageVersion"}, + cmdType: utils.DockerImage, + subScan: utils.ScaScan, + input: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg"))). + WithInvocations([]*sarif.Invocation{ + sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd)), + }, + ), + sarifutils.CreateRunWithDummyResultsInWd(wd, + sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg")), + ), + }, + expectedResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", + sarifutils.CreateDummyResultWithFingerprint("some-msg\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "some-msg", jfrogFingerprintAlgorithmName, "9522c1d915eef55b4a0dc9e160bf5dc7", + sarifutils.CreateDummyLocationWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256"), + ), + ).WithInvocations([]*sarif.Invocation{ + sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd)), + }), + sarifutils.CreateRunWithDummyResultsInWd(wd, + sarifutils.CreateDummyResultWithFingerprint("some-msg\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "some-msg", jfrogFingerprintAlgorithmName, "9522c1d915eef55b4a0dc9e160bf5dc7", + sarifutils.CreateDummyLocationWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256"), + ), + ), + }, + }, + { + name: "Docker image scan - with env vars", + target: results.ScanTarget{Name: "dockerImage:imageVersion"}, + cmdType: utils.DockerImage, + subScan: utils.ScaScan, + withEnvVars: true, + input: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultsInWd(wd, + sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg")), + // No location, should be removed in the output + sarifutils.CreateDummyResult("some-markdown", "some-other-msg", "rule", "level"), + ), + }, + expectedResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultsInWd(wd, + sarifutils.CreateDummyResultWithFingerprint(fmt.Sprintf("some-msg\nGithub Actions Workflow: %s\nRun: 123\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", filepath.Join(GithubBaseWorkflowDir, "workflowFile.yml")), "some-msg", jfrogFingerprintAlgorithmName, "eda26ae830c578197aeda65a82d7f093", + sarifutils.CreateDummyLocationWithPathAndLogicalLocation("", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithPhysicalLocation( + sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewSimpleArtifactLocation(filepath.Join(GithubBaseWorkflowDir, "workflowFile.yml"))), + ), + ), + ), + }, + }, + { + name: "Docker image scan - with Dockerfile in wd", + target: results.ScanTarget{Name: "dockerImage:imageVersion"}, + cmdType: utils.DockerImage, + subScan: utils.ScaScan, + withEnvVars: true, + withDockerfile: true, + input: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultsInWd(dockerfileDir, + sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg")), + ), + }, + expectedResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultsInWd(dockerfileDir, + sarifutils.CreateDummyResultWithFingerprint(fmt.Sprintf("some-msg\nGithub Actions Workflow: %s\nRun: 123\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", filepath.Join(GithubBaseWorkflowDir, "workflowFile.yml")), "some-msg", jfrogFingerprintAlgorithmName, "8cbd7268a4d20f2358ba2667ebd18956", + sarifutils.CreateDummyLocationWithPathAndLogicalLocation("", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithPhysicalLocation( + sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewSimpleArtifactLocation("Dockerfile")), + ), + ), + ), + }, + }, + { + name: "Docker image scan - Secrets", + target: results.ScanTarget{Name: "dockerImage:imageVersion"}, + cmdType: utils.DockerImage, + subScan: utils.SecretsScan, + input: []*sarif.Run{ + sarifutils.CreateRunNameWithResults("some tool name", + sarifutils.CreateDummyResultInPath(fmt.Sprintf("file://%s", filepath.Join(wd, "unpacked", "filesystem", "blobs", "sha1", "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", "usr", "src", "app", "server", "index.js"))), + ).WithInvocations([]*sarif.Invocation{ + sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd)), + }), + }, + expectedResults: []*sarif.Run{ + { + Tool: sarif.Tool{ + Driver: sarifutils.CreateDummyDriver(binarySecretScannerToolName, "", &sarif.ReportingDescriptor{ + ID: "rule", + ShortDescription: sarif.NewMultiformatMessageString("[Secret in Binary found] "), + }), + }, + Invocations: []*sarif.Invocation{sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd))}, + Results: []*sarif.Result{ + sarifutils.CreateDummyResultWithFingerprint(fmt.Sprintf("🔒 Found Secrets in Binary docker scanning:\nImage: dockerImage:imageVersion\nLayer (sha1): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: %s\nEvidence: snippet", filepath.Join("usr", "src", "app", "server", "index.js")), "", jfrogFingerprintAlgorithmName, "dee156c9fd75a4237102dc8fb29277a2", + sarifutils.CreateDummyLocationWithPathAndLogicalLocation(filepath.Join("usr", "src", "app", "server", "index.js"), "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", "layer", "algorithm", "sha1"), + ), + }, + }, + }, + }, + { + name: "Binary scan - SCA", + target: results.ScanTarget{Target: filepath.Join(wd, "dir", "binary")}, + cmdType: utils.Binary, + subScan: utils.ScaScan, + input: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultsInWd(wd, + sarifutils.CreateDummyResultInPath(fmt.Sprintf("file://%s", filepath.Join(wd, "dir", "binary"))), + ), + }, + expectedResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultsInWd(wd, + sarifutils.CreateDummyResultWithFingerprint("", "", jfrogFingerprintAlgorithmName, "e72a936dc73acbc4283a93230ff9b6e8", sarifutils.CreateDummyLocationInPath(filepath.Join("dir", "binary"))), + ), + }, + }, + { + name: "Audit scan - SCA", + target: results.ScanTarget{Target: wd}, + cmdType: utils.SourceCode, + subScan: utils.ScaScan, + input: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultsInWd(wd, + sarifutils.CreateDummyResultInPath(filepath.Join(wd, "Package-Descriptor")), + // No location, should be removed in the output + sarifutils.CreateDummyResult("some-markdown", "some-other-msg", "rule", "level"), + ), + }, + expectedResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultsInWd(wd, + sarifutils.CreateDummyResultInPath("Package-Descriptor"), + ), + }, + }, + { + name: "Audit scan - Secrets", + target: results.ScanTarget{Target: wd}, + cmdType: utils.SourceCode, + subScan: utils.SecretsScan, + input: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultsInWd(wd, + sarifutils.CreateDummyResultInPath(fmt.Sprintf("file://%s", filepath.Join(wd, "dir", "file"))), + // No location, should be removed in the output + sarifutils.CreateDummyResult("some-markdown", "some-other-msg", "rule", "level"), + ), + }, + expectedResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultsInWd(wd, + sarifutils.CreateDummyResultInPath(filepath.Join("dir", "file")), + ), + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if tc.withEnvVars { + cleanFileEnv := clientTests.SetEnvWithCallbackAndAssert(t, CurrentWorkflowNameEnvVar, "workflow name") + defer cleanFileEnv() + cleanRunNumEnv := clientTests.SetEnvWithCallbackAndAssert(t, CurrentWorkflowRunNumberEnvVar, "123") + defer cleanRunNumEnv() + } else { + // Since the the env are provided by the + cleanFileEnv := clientTests.SetEnvWithCallbackAndAssert(t, CurrentWorkflowNameEnvVar, "") + defer cleanFileEnv() + cleanRunNumEnv := clientTests.SetEnvWithCallbackAndAssert(t, CurrentWorkflowRunNumberEnvVar, "") + defer cleanRunNumEnv() + } + if tc.withDockerfile { + revertWd := clientTests.ChangeDirWithCallback(t, wd, dockerfileDir) + defer revertWd() + } + patchRunsToPassIngestionRules(tc.cmdType, tc.subScan, tc.target, tc.input...) + assert.ElementsMatch(t, tc.expectedResults, tc.input) + }) + } +} diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go index f37b8015..a5f000b8 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go @@ -43,30 +43,30 @@ func (sjc *CmdResultsSimpleJsonConverter) Get() *formats.SimpleJsonResults { return sjc.current } -func (sjc *CmdResultsSimpleJsonConverter) Reset(multiScanId, _ string, entitledForJas, multipleTargets bool) (err error) { +func (sjc *CmdResultsSimpleJsonConverter) Reset(_ utils.CommandType, multiScanId, _ string, entitledForJas, multipleTargets bool) (err error) { sjc.current = &formats.SimpleJsonResults{MultiScanId: multiScanId} sjc.entitledForJas = entitledForJas sjc.multipleRoots = multipleTargets return } -func (sjc *CmdResultsSimpleJsonConverter) ParseNewTargetResults(target string, errors ...error) (err error) { +func (sjc *CmdResultsSimpleJsonConverter) ParseNewTargetResults(target results.ScanTarget, errors ...error) (err error) { if sjc.current == nil { - return results.ConvertorResetErr + return results.ErrConvertorReset } for _, err := range errors { if err != nil { - sjc.current.Errors = append(sjc.current.Errors, formats.SimpleJsonError{FilePath: target, ErrorMessage: err.Error()}) + sjc.current.Errors = append(sjc.current.Errors, formats.SimpleJsonError{FilePath: target.Target, ErrorMessage: err.Error()}) } } return } -func (sjc *CmdResultsSimpleJsonConverter) ParseViolations(target string, _ techutils.Technology, violations []services.Violation, applicabilityRuns ...*sarif.Run) (err error) { +func (sjc *CmdResultsSimpleJsonConverter) ParseViolations(target results.ScanTarget, scaResponse services.ScanResponse, applicabilityRuns ...*sarif.Run) (err error) { if sjc.current == nil { - return results.ConvertorResetErr + return results.ErrConvertorReset } - secViolationsSimpleJson, licViolationsSimpleJson, opRiskViolationsSimpleJson, err := PrepareSimpleJsonViolations(target, violations, sjc.pretty, sjc.entitledForJas, applicabilityRuns...) + secViolationsSimpleJson, licViolationsSimpleJson, opRiskViolationsSimpleJson, err := PrepareSimpleJsonViolations(target, scaResponse, sjc.pretty, sjc.entitledForJas, applicabilityRuns...) if err != nil { return } @@ -76,11 +76,11 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseViolations(target string, _ techu return } -func (sjc *CmdResultsSimpleJsonConverter) ParseVulnerabilities(target string, _ techutils.Technology, vulnerabilities []services.Vulnerability, applicabilityRuns ...*sarif.Run) (err error) { +func (sjc *CmdResultsSimpleJsonConverter) ParseVulnerabilities(target results.ScanTarget, scaResponse services.ScanResponse, applicabilityRuns ...*sarif.Run) (err error) { if sjc.current == nil { - return results.ConvertorResetErr + return results.ErrConvertorReset } - vulSimpleJson, err := PrepareSimpleJsonVulnerabilities(target, vulnerabilities, sjc.pretty, sjc.entitledForJas, applicabilityRuns...) + vulSimpleJson, err := PrepareSimpleJsonVulnerabilities(target, scaResponse, sjc.pretty, sjc.entitledForJas, applicabilityRuns...) if err != nil || len(vulSimpleJson) == 0 { return } @@ -88,9 +88,9 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseVulnerabilities(target string, _ return } -func (sjc *CmdResultsSimpleJsonConverter) ParseLicenses(target string, _ techutils.Technology, licenses []services.License) (err error) { +func (sjc *CmdResultsSimpleJsonConverter) ParseLicenses(target results.ScanTarget, licenses []services.License) (err error) { if sjc.current == nil { - return results.ConvertorResetErr + return results.ErrConvertorReset } licSimpleJson, err := PrepareSimpleJsonLicenses(target, licenses) if err != nil || len(licSimpleJson) == 0 { @@ -100,12 +100,12 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseLicenses(target string, _ techuti return } -func (sjc *CmdResultsSimpleJsonConverter) ParseSecrets(target string, secrets ...*sarif.Run) (err error) { +func (sjc *CmdResultsSimpleJsonConverter) ParseSecrets(target results.ScanTarget, secrets ...*sarif.Run) (err error) { if !sjc.entitledForJas { return } if sjc.current == nil { - return results.ConvertorResetErr + return results.ErrConvertorReset } secretsSimpleJson, err := PrepareSimpleJsonJasIssues(target, sjc.entitledForJas, sjc.pretty, secrets...) if err != nil || len(secretsSimpleJson) == 0 { @@ -115,12 +115,12 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseSecrets(target string, secrets .. return } -func (sjc *CmdResultsSimpleJsonConverter) ParseIacs(target string, iacs ...*sarif.Run) (err error) { +func (sjc *CmdResultsSimpleJsonConverter) ParseIacs(target results.ScanTarget, iacs ...*sarif.Run) (err error) { if !sjc.entitledForJas { return } if sjc.current == nil { - return results.ConvertorResetErr + return results.ErrConvertorReset } iacSimpleJson, err := PrepareSimpleJsonJasIssues(target, sjc.entitledForJas, sjc.pretty, iacs...) if err != nil || len(iacSimpleJson) == 0 { @@ -130,12 +130,12 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseIacs(target string, iacs ...*sari return } -func (sjc *CmdResultsSimpleJsonConverter) ParseSast(target string, sast ...*sarif.Run) (err error) { +func (sjc *CmdResultsSimpleJsonConverter) ParseSast(target results.ScanTarget, sast ...*sarif.Run) (err error) { if !sjc.entitledForJas { return } if sjc.current == nil { - return results.ConvertorResetErr + return results.ErrConvertorReset } sastSimpleJson, err := PrepareSimpleJsonJasIssues(target, sjc.entitledForJas, sjc.pretty, sast...) if err != nil || len(sastSimpleJson) == 0 { @@ -145,13 +145,13 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseSast(target string, sast ...*sari return } -func PrepareSimpleJsonViolations(target string, violations []services.Violation, pretty, jasEntitled bool, applicabilityRuns ...*sarif.Run) ([]formats.VulnerabilityOrViolationRow, []formats.LicenseRow, []formats.OperationalRiskViolationRow, error) { +func PrepareSimpleJsonViolations(target results.ScanTarget, scaResponse services.ScanResponse, pretty, jasEntitled bool, applicabilityRuns ...*sarif.Run) ([]formats.VulnerabilityOrViolationRow, []formats.LicenseRow, []formats.OperationalRiskViolationRow, error) { var securityViolationsRows []formats.VulnerabilityOrViolationRow var licenseViolationsRows []formats.LicenseRow var operationalRiskViolationsRows []formats.OperationalRiskViolationRow - err := results.PrepareScaViolations( + _, _, err := results.PrepareScaViolations( target, - violations, + scaResponse.Violations, pretty, jasEntitled, applicabilityRuns, @@ -162,11 +162,11 @@ func PrepareSimpleJsonViolations(target string, violations []services.Violation, return securityViolationsRows, licenseViolationsRows, operationalRiskViolationsRows, err } -func PrepareSimpleJsonVulnerabilities(target string, vulnerabilities []services.Vulnerability, pretty, entitledForJas bool, applicabilityRuns ...*sarif.Run) ([]formats.VulnerabilityOrViolationRow, error) { +func PrepareSimpleJsonVulnerabilities(target results.ScanTarget, scaResponse services.ScanResponse, pretty, entitledForJas bool, applicabilityRuns ...*sarif.Run) ([]formats.VulnerabilityOrViolationRow, error) { var vulnerabilitiesRows []formats.VulnerabilityOrViolationRow err := results.PrepareScaVulnerabilities( target, - vulnerabilities, + scaResponse.Vulnerabilities, pretty, entitledForJas, applicabilityRuns, @@ -175,7 +175,7 @@ func PrepareSimpleJsonVulnerabilities(target string, vulnerabilities []services. return vulnerabilitiesRows, err } -func addSimpleJsonVulnerability(vulnerabilitiesRows *[]formats.VulnerabilityOrViolationRow, pretty bool) results.PrepareScaVulnerabilityFunc { +func addSimpleJsonVulnerability(vulnerabilitiesRows *[]formats.VulnerabilityOrViolationRow, pretty bool) results.ParseScaVulnerabilityFunc { return func(vulnerability services.Vulnerability, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { *vulnerabilitiesRows = append(*vulnerabilitiesRows, formats.VulnerabilityOrViolationRow{ @@ -201,7 +201,7 @@ func addSimpleJsonVulnerability(vulnerabilitiesRows *[]formats.VulnerabilityOrVi } } -func addSimpleJsonSecurityViolation(securityViolationsRows *[]formats.VulnerabilityOrViolationRow, pretty bool) results.PrepareScaViolationFunc { +func addSimpleJsonSecurityViolation(securityViolationsRows *[]formats.VulnerabilityOrViolationRow, pretty bool) results.ParseScaViolationFunc { return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { *securityViolationsRows = append(*securityViolationsRows, formats.VulnerabilityOrViolationRow{ @@ -227,7 +227,7 @@ func addSimpleJsonSecurityViolation(securityViolationsRows *[]formats.Vulnerabil } } -func addSimpleJsonLicenseViolation(licenseViolationsRows *[]formats.LicenseRow, pretty bool) results.PrepareScaViolationFunc { +func addSimpleJsonLicenseViolation(licenseViolationsRows *[]formats.LicenseRow, pretty bool) results.ParseScaViolationFunc { return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { *licenseViolationsRows = append(*licenseViolationsRows, formats.LicenseRow{ @@ -245,7 +245,7 @@ func addSimpleJsonLicenseViolation(licenseViolationsRows *[]formats.LicenseRow, } } -func addSimpleJsonOperationalRiskViolation(operationalRiskViolationsRows *[]formats.OperationalRiskViolationRow, pretty bool) results.PrepareScaViolationFunc { +func addSimpleJsonOperationalRiskViolation(operationalRiskViolationsRows *[]formats.OperationalRiskViolationRow, pretty bool) results.ParseScaViolationFunc { return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { violationOpRiskData := getOperationalRiskViolationReadableData(violation) for compIndex := 0; compIndex < len(impactedPackagesName); compIndex++ { @@ -272,13 +272,13 @@ func addSimpleJsonOperationalRiskViolation(operationalRiskViolationsRows *[]form } } -func PrepareSimpleJsonLicenses(target string, licenses []services.License) ([]formats.LicenseRow, error) { +func PrepareSimpleJsonLicenses(target results.ScanTarget, licenses []services.License) ([]formats.LicenseRow, error) { var licensesRows []formats.LicenseRow err := results.PrepareLicenses(target, licenses, addSimpleJsonLicense(&licensesRows)) return licensesRows, err } -func addSimpleJsonLicense(licenseViolationsRows *[]formats.LicenseRow) results.PrepareLicensesFunc { +func addSimpleJsonLicense(licenseViolationsRows *[]formats.LicenseRow) results.ParseLicensesFunc { return func(license services.License, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { *licenseViolationsRows = append(*licenseViolationsRows, formats.LicenseRow{ @@ -296,7 +296,7 @@ func addSimpleJsonLicense(licenseViolationsRows *[]formats.LicenseRow) results.P } } -func PrepareSimpleJsonJasIssues(target string, entitledForJas, pretty bool, jasIssues ...*sarif.Run) ([]formats.SourceCodeRow, error) { +func PrepareSimpleJsonJasIssues(target results.ScanTarget, entitledForJas, pretty bool, jasIssues ...*sarif.Run) ([]formats.SourceCodeRow, error) { var rows []formats.SourceCodeRow err := results.PrepareJasIssues(target, jasIssues, entitledForJas, func(run *sarif.Run, rule *sarif.ReportingDescriptor, severity severityutils.Severity, result *sarif.Result, location *sarif.Location) error { scannerDescription := "" @@ -420,7 +420,7 @@ func removeScaDuplications(issues []formats.VulnerabilityOrViolationRow, multipl packageKey := results.GetUniqueKey(issues[i].ImpactedDependencyDetails.ImpactedDependencyName, issues[i].ImpactedDependencyDetails.ImpactedDependencyVersion, issues[i].IssueId, len(issues[i].FixedVersions) > 0) if uniqueIssue, exist := uniqueIssues[packageKey]; exist { // combine attributes from the same issue - uniqueIssue.FixedVersions = utils.UniqueUnion(uniqueIssue.FixedVersions, issues[i].FixedVersions...) + uniqueIssue.FixedVersions = utils.UniqueIntersection(uniqueIssue.FixedVersions, issues[i].FixedVersions...) uniqueIssue.ImpactPaths = AppendImpactPathsIfUnique(uniqueIssue.ImpactPaths, issues[i].ImpactPaths, multipleRoots) uniqueIssue.ImpactedDependencyDetails.Components = AppendComponentIfUnique(uniqueIssue.ImpactedDependencyDetails.Components, issues[i].ImpactedDependencyDetails.Components) continue diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go index c4ec13be..484d6c93 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go @@ -1,6 +1,7 @@ package simplejsonparser import ( + "path/filepath" "testing" "github.com/owenrumney/go-sarif/v2/sarif" @@ -10,6 +11,7 @@ import ( "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-client-go/xray/services" ) @@ -233,7 +235,6 @@ func TestSortVulnerabilityOrViolationRows(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { sortVulnerabilityOrViolationRows(tc.rows) - for i, row := range tc.rows { assert.Equal(t, tc.expectedOrder[i], row.ImpactedDependencyName) } @@ -266,28 +267,28 @@ func TestGetOperationalRiskReadableData(t *testing.T) { func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { testCases := []struct { - name string - input []services.Vulnerability - target string - entitledForJas bool - applicablityRuns []*sarif.Run - expectedOutput []formats.VulnerabilityOrViolationRow + name string + input []services.Vulnerability + target results.ScanTarget + entitledForJas bool + applicabilityRuns []*sarif.Run + expectedOutput []formats.VulnerabilityOrViolationRow }{ { name: "No vulnerabilities", - target: "target", + target: results.ScanTarget{Target: "target"}, }, { name: "Vulnerabilities not entitled for JAS", input: testScaScanVulnerabilities, - target: "target", + target: results.ScanTarget{Target: "target"}, expectedOutput: []formats.VulnerabilityOrViolationRow{ { Summary: "summary-1", IssueId: "XRAY-1", Cves: []formats.CveRow{{Id: "CVE-1"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 17}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 15}, ImpactedDependencyName: "component-A", // Direct Components: []formats.ComponentRow{{ @@ -302,7 +303,7 @@ func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { IssueId: "XRAY-1", Cves: []formats.CveRow{{Id: "CVE-1"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 17}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 15}, ImpactedDependencyName: "component-B", // Direct Components: []formats.ComponentRow{{ @@ -317,7 +318,7 @@ func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { IssueId: "XRAY-2", Cves: []formats.CveRow{{Id: "CVE-2"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 11}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 9}, ImpactedDependencyName: "component-B", // Direct Components: []formats.ComponentRow{{ @@ -332,9 +333,9 @@ func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { { name: "Vulnerabilities with Jas", input: testScaScanVulnerabilities, - target: "target", + target: results.ScanTarget{Target: "target"}, entitledForJas: true, - applicablityRuns: []*sarif.Run{ + applicabilityRuns: []*sarif.Run{ sarifutils.CreateRunWithDummyResultAndRuleProperties( "applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_CVE-1"), ).WithInvocations([]*sarif.Invocation{ @@ -410,7 +411,7 @@ func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - out, err := PrepareSimpleJsonVulnerabilities(tc.target, tc.input, false, tc.entitledForJas, tc.applicablityRuns...) + out, err := PrepareSimpleJsonVulnerabilities(tc.target, services.ScanResponse{Vulnerabilities: tc.input}, false, tc.entitledForJas, tc.applicabilityRuns...) assert.NoError(t, err) assert.ElementsMatch(t, tc.expectedOutput, out) }) @@ -421,28 +422,28 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { testCases := []struct { name string input []services.Violation - target string + target results.ScanTarget entitledForJas bool - applicablityRuns []*sarif.Run + applicabilityRuns []*sarif.Run expectedSecurityOutput []formats.VulnerabilityOrViolationRow expectedLicenseOutput []formats.LicenseRow expectedOperationalRiskOutput []formats.OperationalRiskViolationRow }{ { name: "No violations", - target: "target", + target: results.ScanTarget{Target: "target"}, }, { name: "Violations not entitled for JAS", input: testScaScanViolation, - target: "target", + target: results.ScanTarget{Target: "target"}, expectedSecurityOutput: []formats.VulnerabilityOrViolationRow{ { Summary: "summary-1", IssueId: "XRAY-1", Cves: []formats.CveRow{{Id: "CVE-1"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 17}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 15}, ImpactedDependencyName: "component-A", // Direct Components: []formats.ComponentRow{{ @@ -457,7 +458,7 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { IssueId: "XRAY-1", Cves: []formats.CveRow{{Id: "CVE-1"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 17}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 15}, ImpactedDependencyName: "component-B", // Direct Components: []formats.ComponentRow{{ @@ -472,7 +473,7 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { IssueId: "XRAY-2", Cves: []formats.CveRow{{Id: "CVE-2"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 11}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 9}, ImpactedDependencyName: "component-B", // Direct Components: []formats.ComponentRow{{ @@ -487,7 +488,7 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { { LicenseKey: "license-1", ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 11}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 9}, ImpactedDependencyName: "component-B", Components: []formats.ComponentRow{{Name: "component-B", Location: &formats.Location{File: "target"}}}, }, @@ -497,9 +498,9 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { { name: "Violations with applicability", input: testScaScanViolation, - target: "target", + target: results.ScanTarget{Target: "target"}, entitledForJas: true, - applicablityRuns: []*sarif.Run{ + applicabilityRuns: []*sarif.Run{ sarifutils.CreateRunWithDummyResultAndRuleProperties( "applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_CVE-1"), ).WithInvocations([]*sarif.Invocation{ @@ -589,7 +590,7 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - securityOutput, licenseOutput, operationalRiskOutput, err := PrepareSimpleJsonViolations(tc.target, tc.input, false, tc.entitledForJas, tc.applicablityRuns...) + securityOutput, licenseOutput, operationalRiskOutput, err := PrepareSimpleJsonViolations(tc.target, services.ScanResponse{Violations: tc.input}, false, tc.entitledForJas, tc.applicabilityRuns...) assert.NoError(t, err) assert.ElementsMatch(t, tc.expectedSecurityOutput, securityOutput) assert.ElementsMatch(t, tc.expectedLicenseOutput, licenseOutput) @@ -600,9 +601,101 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { } func TestPrepareSimpleJsonLicenses(t *testing.T) { - + testCases := []struct { + name string + target results.ScanTarget + licenses []services.License + expectedOutput []formats.LicenseRow + }{ + { + name: "No licenses", + target: results.ScanTarget{Target: "target"}, + }, + { + name: "Licenses", + target: results.ScanTarget{Target: "target"}, + licenses: []services.License{ + { + Key: "license-1", + Name: "license-1-name", + Components: map[string]services.Component{ + "component-B": { + ImpactPaths: [][]services.ImpactPathNode{{ + {ComponentId: "root"}, + {ComponentId: "component-B"}, + }}, + }, + }, + }, + }, + expectedOutput: []formats.LicenseRow{ + { + LicenseKey: "license-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + ImpactedDependencyName: "component-B", + // Direct + Components: []formats.ComponentRow{{ + Name: "component-B", + Location: &formats.Location{File: "target"}, + }}, + }, + ImpactPaths: [][]formats.ComponentRow{{{Name: "root"}, {Name: "component-B"}}}, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + out, err := PrepareSimpleJsonLicenses(tc.target, tc.licenses) + assert.NoError(t, err) + assert.ElementsMatch(t, tc.expectedOutput, out) + }) + } } func TestPrepareSimpleJsonJasIssues(t *testing.T) { - + issues := []*sarif.Run{ + // Secret detection + sarifutils.CreateRunWithDummyResultsInWd("target", + sarifutils.CreateResultWithOneLocation(filepath.Join("target", "file"), 1, 2, 3, 4, "secret-snippet", "secret-rule-id", "note"), + ), + } + testCases := []struct { + name string + target results.ScanTarget + entitledForJas bool + jasIssues []*sarif.Run + expectedOutput []formats.SourceCodeRow + }{ + { + name: "No JAS issues", + entitledForJas: true, + target: results.ScanTarget{Target: filepath.Join("root", "target")}, + }, + { + name: "JAS issues - not entitled", + target: results.ScanTarget{Target: "target"}, + jasIssues: issues, + expectedOutput: []formats.SourceCodeRow{}, + }, + { + name: "JAS issues", + entitledForJas: true, + target: results.ScanTarget{Target: "target"}, + jasIssues: issues, + expectedOutput: []formats.SourceCodeRow{ + { + Location: formats.Location{File: "file", StartLine: 1, StartColumn: 2, EndLine: 3, EndColumn: 4, Snippet: "secret-snippet"}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 11}, + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + out, err := PrepareSimpleJsonJasIssues(tc.target, tc.entitledForJas, false, tc.jasIssues...) + assert.NoError(t, err) + assert.ElementsMatch(t, tc.expectedOutput, out) + }) + } } diff --git a/utils/results/conversion/summaryparser/summaryparser.go b/utils/results/conversion/summaryparser/summaryparser.go index ad6180f9..331165b2 100644 --- a/utils/results/conversion/summaryparser/summaryparser.go +++ b/utils/results/conversion/summaryparser/summaryparser.go @@ -2,132 +2,214 @@ package summaryparser import ( "github.com/jfrog/gofrog/datastructures" + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/severityutils" - "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-client-go/xray/services" "github.com/owenrumney/go-sarif/v2/sarif" ) type CmdResultsSummaryConverter struct { - current *formats.SummaryResults - currentScan *formats.ScanSummaryResult - currentCveUnique *datastructures.Set[string] - entitledForJas bool + entitledForJas bool + includeVulnerabilities bool + includeViolations bool + + current *formats.ResultsSummary + currentScan *formats.ScanSummary } -func NewCmdResultsSummaryConverter() *CmdResultsSummaryConverter { - return &CmdResultsSummaryConverter{} +func NewCmdResultsSummaryConverter(includeVulnerabilities, hasViolationContext bool) *CmdResultsSummaryConverter { + return &CmdResultsSummaryConverter{includeVulnerabilities: includeVulnerabilities, includeViolations: hasViolationContext} } -func (sc *CmdResultsSummaryConverter) Get() *formats.SummaryResults { +func (sc *CmdResultsSummaryConverter) Get() *formats.ResultsSummary { if sc.current == nil { - return &formats.SummaryResults{} + return &formats.ResultsSummary{} } // Flush the last scan - if err := sc.ParseNewTargetResults("", nil); err != nil { - return &formats.SummaryResults{} + if err := sc.ParseNewTargetResults(results.ScanTarget{}, nil); err != nil { + return &formats.ResultsSummary{} } return sc.current } -func (sc *CmdResultsSummaryConverter) Reset(_, _ string, entitledForJas, _ bool) (err error) { - sc.current = &formats.SummaryResults{} +func (sc *CmdResultsSummaryConverter) Reset(_ utils.CommandType, _, _ string, entitledForJas, _ bool) (err error) { + sc.current = &formats.ResultsSummary{} sc.entitledForJas = entitledForJas - sc.currentCveUnique = datastructures.MakeSet[string]() return } -func (sc *CmdResultsSummaryConverter) ParseNewTargetResults(target string, _ ...error) (err error) { +func (sc *CmdResultsSummaryConverter) ParseNewTargetResults(target results.ScanTarget, _ ...error) (err error) { if sc.current == nil { - return results.ConvertorResetErr + return results.ErrConvertorReset } if sc.currentScan != nil { sc.current.Scans = append(sc.current.Scans, *sc.currentScan) } - sc.currentScan = &formats.ScanSummaryResult{Target: target} + sc.currentScan = &formats.ScanSummary{Target: target.Target, Name: target.Name} + if sc.includeVulnerabilities { + sc.currentScan.Vulnerabilities = &formats.ScanResultSummary{} + } + if sc.includeViolations { + sc.currentScan.Violations = &formats.ScanViolationsSummary{ScanResultSummary: formats.ScanResultSummary{}} + } return } -func (sc *CmdResultsSummaryConverter) ParseViolations(target string, _ techutils.Technology, violations []services.Violation, applicabilityRuns ...*sarif.Run) (err error) { +// validateBeforeParse checks if the parser is initialized to parse results (checks if Reset and at least one ParseNewTargetResults was called before) +func (sc *CmdResultsSummaryConverter) validateBeforeParse() (err error) { if sc.current == nil { - return results.ConvertorResetErr + return results.ErrConvertorReset } if sc.currentScan == nil { - return results.ConvertorNewScanErr + return results.ErrConvertorNewScan + } + return +} + +func (sc *CmdResultsSummaryConverter) ParseViolations(target results.ScanTarget, scaResponse services.ScanResponse, applicabilityRuns ...*sarif.Run) (err error) { + if err = sc.validateBeforeParse(); err != nil || sc.currentScan.Violations == nil { + return } - err = results.PrepareScaViolations( + if sc.currentScan.Violations.ScanResultSummary.ScaResults == nil { + sc.currentScan.Violations.ScanResultSummary.ScaResults = &formats.ScaScanResultSummary{} + } + // Parse general SCA results + if scaResponse.ScanId != "" { + sc.currentScan.Violations.ScanResultSummary.ScaResults.ScanIds = utils.UniqueUnion(sc.currentScan.Violations.ScanResultSummary.ScaResults.ScanIds, scaResponse.ScanId) + } + if scaResponse.XrayDataUrl != "" { + sc.currentScan.Violations.ScanResultSummary.ScaResults.MoreInfoUrls = utils.UniqueUnion(sc.currentScan.Violations.ScanResultSummary.ScaResults.MoreInfoUrls, scaResponse.XrayDataUrl) + } + // Parse violations + parsed := datastructures.MakeSet[string]() + watches, failBuild, err := results.PrepareScaViolations( target, - violations, + scaResponse.Violations, false, sc.entitledForJas, applicabilityRuns, - sc.getScaViolationHandler(), - sc.getScaViolationHandler(), - sc.getScaViolationHandler(), + sc.getScaSecurityViolationHandler(parsed), + sc.getScaLicenseViolationHandler(parsed), + sc.getScaOperationalRiskViolationHandler(parsed), ) + if err != nil { + return + } + sc.currentScan.Violations.Watches = utils.UniqueUnion(sc.currentScan.Violations.Watches, watches...) + sc.currentScan.Violations.FailBuild = sc.currentScan.Violations.FailBuild || failBuild return } -func (sc *CmdResultsSummaryConverter) getScaViolationHandler() results.PrepareScaViolationFunc { +func (sc *CmdResultsSummaryConverter) getScaSecurityViolationHandler(parsed *datastructures.Set[string]) results.ParseScaViolationFunc { return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) (err error) { - if sc.currentScan.Violations == nil { - sc.currentScan.Violations = formats.TwoLevelSummaryCount{} + for _, id := range getCveIds(cves, violation.IssueId) { + // PrepareScaViolations calls the handler for each violation and impacted component pair, we want to count unique violations + key := violation.WatchName + id + if parsed.Exists(key) { + continue + } + parsed.Add(key) + // Count the violation + scaSecurityHandler(sc.currentScan.Violations.ScanResultSummary.ScaResults, severity, applicabilityStatus) } - if sc.currentScan.Violations[violation.ViolationType] == nil { - sc.currentScan.Violations[violation.ViolationType] = formats.SummaryCount{} + return + } +} + +func (sc *CmdResultsSummaryConverter) getScaLicenseViolationHandler(parsed *datastructures.Set[string]) results.ParseScaViolationFunc { + return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) (err error) { + if sc.currentScan.Violations.ScaResults.License == nil { + sc.currentScan.Violations.ScaResults.License = formats.ResultSummary{} } - for i := 0; i < len(getCveIds(cves, violation.IssueId)); i++ { - sc.currentScan.Violations[violation.ViolationType][severity.String()]++ + // PrepareScaViolations calls the handler for each violation and impacted component pair, we want to count unique violations + key := violation.WatchName + violation.IssueId + if parsed.Exists(key) { + return + } + parsed.Add(key) + if _, ok := sc.currentScan.Violations.ScaResults.License[severity.String()]; !ok { + sc.currentScan.Violations.ScaResults.License[severity.String()] = map[string]int{} } + sc.currentScan.Violations.ScaResults.License[severity.String()][formats.NoStatus]++ return } } -func (sc *CmdResultsSummaryConverter) ParseVulnerabilities(target string, tech techutils.Technology, vulnerabilities []services.Vulnerability, applicabilityRuns ...*sarif.Run) (err error) { - if sc.current == nil { - return results.ConvertorResetErr +func (sc *CmdResultsSummaryConverter) getScaOperationalRiskViolationHandler(parsed *datastructures.Set[string]) results.ParseScaViolationFunc { + return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) (err error) { + if sc.currentScan.Violations.ScaResults.OperationalRisk == nil { + sc.currentScan.Violations.ScaResults.OperationalRisk = formats.ResultSummary{} + } + // PrepareScaViolations calls the handler for each violation and impacted component pair, we want to count unique violations + key := violation.WatchName + violation.IssueId + if parsed.Exists(key) { + return + } + parsed.Add(key) + if _, ok := sc.currentScan.Violations.ScaResults.OperationalRisk[severity.String()]; !ok { + sc.currentScan.Violations.ScaResults.OperationalRisk[severity.String()] = map[string]int{} + } + sc.currentScan.Violations.ScaResults.OperationalRisk[severity.String()][formats.NoStatus]++ + return } - if sc.currentScan == nil { - return results.ConvertorNewScanErr +} + +func (sc *CmdResultsSummaryConverter) ParseVulnerabilities(target results.ScanTarget, scaResponse services.ScanResponse, applicabilityRuns ...*sarif.Run) (err error) { + if err = sc.validateBeforeParse(); err != nil || sc.currentScan.Vulnerabilities == nil { + return + } + if sc.currentScan.Vulnerabilities.ScaResults == nil { + sc.currentScan.Vulnerabilities.ScaResults = &formats.ScaScanResultSummary{} } + // Parse general SCA results + if scaResponse.ScanId != "" { + sc.currentScan.Vulnerabilities.ScaResults.ScanIds = utils.UniqueUnion(sc.currentScan.Vulnerabilities.ScaResults.ScanIds, scaResponse.ScanId) + } + if scaResponse.XrayDataUrl != "" { + sc.currentScan.Vulnerabilities.ScaResults.MoreInfoUrls = utils.UniqueUnion(sc.currentScan.Vulnerabilities.ScaResults.MoreInfoUrls, scaResponse.XrayDataUrl) + } + // Parse vulnerabilities + parsed := datastructures.MakeSet[string]() err = results.PrepareScaVulnerabilities( target, - vulnerabilities, + scaResponse.Vulnerabilities, false, sc.entitledForJas, applicabilityRuns, - func(vulnerability services.Vulnerability, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error { - for _, id := range getCveIds(cves, vulnerability.IssueId) { - sc.addVulnerabilityToScanSummaryResult(id, impactedPackagesName, impactedPackagesVersion, severity, applicabilityStatus) - } - return nil - }, + sc.getScaVulnerabilityHandler(parsed), ) return } -func (sc *CmdResultsSummaryConverter) addVulnerabilityToScanSummaryResult(id, impactedPackagesName, impactedPackagesVersion string, severity severityutils.Severity, applicabilityStatus jasutils.ApplicabilityStatus) { - if sc.currentScan.Vulnerabilities == nil { - sc.currentScan.Vulnerabilities = &formats.ScanVulnerabilitiesSummary{} - } - if sc.currentScan.Vulnerabilities.ScaScanResults == nil { - sc.currentScan.Vulnerabilities.ScaScanResults = &formats.ScanScaResult{SummaryCount: formats.TwoLevelSummaryCount{}} +func (sc *CmdResultsSummaryConverter) getScaVulnerabilityHandler(parsed *datastructures.Set[string]) results.ParseScaVulnerabilityFunc { + return func(vulnerability services.Vulnerability, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) (err error) { + for _, id := range getCveIds(cves, vulnerability.IssueId) { + // PrepareScaVulnerabilities calls the handler for each vulnerability and impacted component pair, we want to count unique vulnerabilities + if parsed.Exists(id) { + continue + } + parsed.Add(id) + // Count the vulnerability + scaSecurityHandler(sc.currentScan.Vulnerabilities.ScaResults, severity, applicabilityStatus) + } + return } - if sc.currentScan.Vulnerabilities.ScaScanResults.SummaryCount == nil { - sc.currentScan.Vulnerabilities.ScaScanResults.SummaryCount = formats.TwoLevelSummaryCount{} +} + +func scaSecurityHandler(scaResults *formats.ScaScanResultSummary, severity severityutils.Severity, applicabilityStatus jasutils.ApplicabilityStatus) { + if scaResults.Security == nil { + scaResults.Security = formats.ResultSummary{} } - if sc.currentScan.Vulnerabilities.ScaScanResults.SummaryCount[severity.String()] == nil { - sc.currentScan.Vulnerabilities.ScaScanResults.SummaryCount[severity.String()] = formats.SummaryCount{} + if _, ok := scaResults.Security[severity.String()]; !ok { + scaResults.Security[severity.String()] = map[string]int{} } - issueId := results.GetScaIssueId(impactedPackagesName, impactedPackagesVersion, id) - if !sc.currentCveUnique.Exists(issueId) { - sc.currentScan.Vulnerabilities.ScaScanResults.UniqueFindings++ - sc.currentCveUnique.Add(issueId) + if _, ok := scaResults.Security[severity.String()][applicabilityStatus.String()]; !ok { + scaResults.Security[severity.String()][applicabilityStatus.String()] = 0 } - sc.currentScan.Vulnerabilities.ScaScanResults.SummaryCount[severity.String()][applicabilityStatus.String()]++ + scaResults.Security[severity.String()][applicabilityStatus.String()]++ } func getCveIds(cves []formats.CveRow, issueId string) []string { @@ -141,86 +223,77 @@ func getCveIds(cves []formats.CveRow, issueId string) []string { return ids } -func (sc *CmdResultsSummaryConverter) ParseLicenses(target string, tech techutils.Technology, licenses []services.License) (err error) { +func (sc *CmdResultsSummaryConverter) ParseLicenses(target results.ScanTarget, licenses []services.License) (err error) { // Not supported in the summary return } -func (sc *CmdResultsSummaryConverter) ParseSecrets(target string, secrets ...*sarif.Run) (err error) { - if !sc.entitledForJas { +func (sc *CmdResultsSummaryConverter) ParseSecrets(target results.ScanTarget, secrets ...*sarif.Run) (err error) { + if !sc.entitledForJas || sc.currentScan.Vulnerabilities == nil { + // JAS results are only supported as vulnerabilities for now return } - if sc.current == nil { - return results.ConvertorResetErr - } - if sc.currentScan == nil { - return results.ConvertorNewScanErr - } - if sc.currentScan.Vulnerabilities == nil { - sc.currentScan.Vulnerabilities = &formats.ScanVulnerabilitiesSummary{} + if err = sc.validateBeforeParse(); err != nil { + return } - if sc.currentScan.Vulnerabilities.SecretsScanResults == nil { - sc.currentScan.Vulnerabilities.SecretsScanResults = &formats.SummaryCount{} + if sc.currentScan.Vulnerabilities.SecretsResults == nil { + sc.currentScan.Vulnerabilities.SecretsResults = &formats.ResultSummary{} } return results.PrepareJasIssues(target, secrets, sc.entitledForJas, sc.getJasHandler(jasutils.Secrets)) } -func (sc *CmdResultsSummaryConverter) ParseIacs(target string, iacs ...*sarif.Run) (err error) { - if !sc.entitledForJas { +func (sc *CmdResultsSummaryConverter) ParseIacs(target results.ScanTarget, iacs ...*sarif.Run) (err error) { + if !sc.entitledForJas || sc.currentScan.Vulnerabilities == nil { + // JAS results are only supported as vulnerabilities for now return } - if sc.current == nil { - return results.ConvertorResetErr - } - if sc.currentScan == nil { - return results.ConvertorNewScanErr - } - if sc.currentScan.Vulnerabilities == nil { - sc.currentScan.Vulnerabilities = &formats.ScanVulnerabilitiesSummary{} + if err = sc.validateBeforeParse(); err != nil { + return } - if sc.currentScan.Vulnerabilities.IacScanResults == nil { - sc.currentScan.Vulnerabilities.IacScanResults = &formats.SummaryCount{} + if sc.currentScan.Vulnerabilities.IacResults == nil { + sc.currentScan.Vulnerabilities.IacResults = &formats.ResultSummary{} } return results.PrepareJasIssues(target, iacs, sc.entitledForJas, sc.getJasHandler(jasutils.IaC)) } -func (sc *CmdResultsSummaryConverter) ParseSast(target string, sast ...*sarif.Run) (err error) { - if !sc.entitledForJas { +func (sc *CmdResultsSummaryConverter) ParseSast(target results.ScanTarget, sast ...*sarif.Run) (err error) { + if !sc.entitledForJas || sc.currentScan.Vulnerabilities == nil { + // JAS results are only supported as vulnerabilities for now return } - if sc.current == nil { - return results.ConvertorResetErr - } - if sc.currentScan == nil { - return results.ConvertorNewScanErr - } - if sc.currentScan.Vulnerabilities == nil { - sc.currentScan.Vulnerabilities = &formats.ScanVulnerabilitiesSummary{} + if err = sc.validateBeforeParse(); err != nil { + return } - if sc.currentScan.Vulnerabilities.SastScanResults == nil { - sc.currentScan.Vulnerabilities.SastScanResults = &formats.SummaryCount{} + if sc.currentScan.Vulnerabilities.SastResults == nil { + sc.currentScan.Vulnerabilities.SastResults = &formats.ResultSummary{} } return results.PrepareJasIssues(target, sast, sc.entitledForJas, sc.getJasHandler(jasutils.Sast)) } -func (sc *CmdResultsSummaryConverter) getJasHandler(scanType jasutils.JasScanType) results.PrepareJasFunc { +func (sc *CmdResultsSummaryConverter) getJasHandler(scanType jasutils.JasScanType) results.ParseJasFunc { return func(run *sarif.Run, rule *sarif.ReportingDescriptor, severity severityutils.Severity, result *sarif.Result, location *sarif.Location) (err error) { if location == nil { + // Only count the issue if it has a location return } - var count *formats.SummaryCount + // Get the scanType count + var count *formats.ResultSummary switch scanType { case jasutils.Secrets: - count = sc.currentScan.Vulnerabilities.SecretsScanResults + count = sc.currentScan.Vulnerabilities.SecretsResults case jasutils.IaC: - count = sc.currentScan.Vulnerabilities.IacScanResults + count = sc.currentScan.Vulnerabilities.IacResults case jasutils.Sast: - count = sc.currentScan.Vulnerabilities.SastScanResults + count = sc.currentScan.Vulnerabilities.SastResults } if count == nil { return } - (*count)[severity.String()]++ + // PrepareJasIssues calls the handler for each issue (location) + if _, ok := (*count)[severity.String()]; !ok { + (*count)[severity.String()] = map[string]int{} + } + (*count)[severity.String()][formats.NoStatus] += 1 return } } diff --git a/utils/results/conversion/summaryparser/summaryparser_test.go b/utils/results/conversion/summaryparser/summaryparser_test.go index 45a661c3..9f4234d0 100644 --- a/utils/results/conversion/summaryparser/summaryparser_test.go +++ b/utils/results/conversion/summaryparser/summaryparser_test.go @@ -4,6 +4,8 @@ import ( "testing" "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/severityutils" "github.com/stretchr/testify/assert" ) @@ -41,3 +43,69 @@ func TestGetCveIds(t *testing.T) { }) } } + +func TestScaSecurityHandler(t *testing.T) { + testCases := []struct { + name string + severityCountsToProcess []map[severityutils.Severity]map[jasutils.ApplicabilityStatus]int + expected formats.ScaScanResultSummary + }{ + { + name: "No results", + severityCountsToProcess: []map[severityutils.Severity]map[jasutils.ApplicabilityStatus]int{}, + expected: formats.ScaScanResultSummary{Security: formats.ResultSummary{}}, + }, + { + name: "One result", + severityCountsToProcess: []map[severityutils.Severity]map[jasutils.ApplicabilityStatus]int{ + { + severityutils.Critical: {jasutils.Applicable: 1}, + }, + }, + expected: formats.ScaScanResultSummary{Security: formats.ResultSummary{"Critical": map[string]int{"Applicable": 1}}}, + }, + { + name: "Multiple results", + severityCountsToProcess: []map[severityutils.Severity]map[jasutils.ApplicabilityStatus]int{ + { + severityutils.Critical: {jasutils.Applicable: 1, jasutils.NotApplicable: 1}, + }, + { + severityutils.High: {jasutils.Applicable: 1}, + severityutils.Medium: {jasutils.NotScanned: 1}, + }, + { + severityutils.Low: {jasutils.NotCovered: 1}, + severityutils.High: {jasutils.Applicable: 1}, + }, + { + severityutils.Critical: {jasutils.Applicable: 1, jasutils.NotApplicable: 2}, + severityutils.Low: {jasutils.Applicable: 1}, + }, + }, + expected: formats.ScaScanResultSummary{Security: formats.ResultSummary{ + "Critical": {jasutils.Applicable.String(): 2, jasutils.NotApplicable.String(): 3}, + "High": {jasutils.Applicable.String(): 2}, + "Medium": {jasutils.NotScanned.String(): 1}, + "Low": {jasutils.Applicable.String(): 1, jasutils.NotCovered.String(): 1}, + }}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + scaSummaryResults := &formats.ScaScanResultSummary{Security: formats.ResultSummary{}} + assert.NotNil(t, scaSummaryResults) + for _, severityCounts := range testCase.severityCountsToProcess { + for severity, statusCounts := range severityCounts { + for status, count := range statusCounts { + for i := 0; i < count; i++ { + scaSecurityHandler(scaSummaryResults, severity, status) + } + } + } + } + assert.Equal(t, testCase.expected, *scaSummaryResults) + }) + } +} diff --git a/utils/results/conversion/tableparser/tableparser.go b/utils/results/conversion/tableparser/tableparser.go index bb3bbd9c..f8cc4508 100644 --- a/utils/results/conversion/tableparser/tableparser.go +++ b/utils/results/conversion/tableparser/tableparser.go @@ -3,9 +3,10 @@ package tableparser import ( "github.com/owenrumney/go-sarif/v2/sarif" + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/results/conversion/simplejsonparser" - "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-client-go/xray/services" ) @@ -35,34 +36,34 @@ func (tc *CmdResultsTableConverter) Get() *formats.ResultsTables { } } -func (tc *CmdResultsTableConverter) Reset(multiScanId, xrayVersion string, entitledForJas, multipleTargets bool) (err error) { - return tc.simpleJsonConvertor.Reset(multiScanId, xrayVersion, entitledForJas, multipleTargets) +func (tc *CmdResultsTableConverter) Reset(cmdType utils.CommandType, multiScanId, xrayVersion string, entitledForJas, multipleTargets bool) (err error) { + return tc.simpleJsonConvertor.Reset(cmdType, multiScanId, xrayVersion, entitledForJas, multipleTargets) } -func (tc *CmdResultsTableConverter) ParseNewTargetResults(target string, errors ...error) (err error) { +func (tc *CmdResultsTableConverter) ParseNewTargetResults(target results.ScanTarget, errors ...error) (err error) { return tc.simpleJsonConvertor.ParseNewTargetResults(target, errors...) } -func (tc *CmdResultsTableConverter) ParseViolations(target string, tech techutils.Technology, violations []services.Violation, applicabilityRuns ...*sarif.Run) (err error) { - return tc.simpleJsonConvertor.ParseViolations(target, tech, violations, applicabilityRuns...) +func (tc *CmdResultsTableConverter) ParseViolations(target results.ScanTarget, scaResponse services.ScanResponse, applicabilityRuns ...*sarif.Run) (err error) { + return tc.simpleJsonConvertor.ParseViolations(target, scaResponse, applicabilityRuns...) } -func (tc *CmdResultsTableConverter) ParseVulnerabilities(target string, tech techutils.Technology, vulnerabilities []services.Vulnerability, applicabilityRuns ...*sarif.Run) (err error) { - return tc.simpleJsonConvertor.ParseVulnerabilities(target, tech, vulnerabilities, applicabilityRuns...) +func (tc *CmdResultsTableConverter) ParseVulnerabilities(target results.ScanTarget, scaResponse services.ScanResponse, applicabilityRuns ...*sarif.Run) (err error) { + return tc.simpleJsonConvertor.ParseVulnerabilities(target, scaResponse, applicabilityRuns...) } -func (tc *CmdResultsTableConverter) ParseLicenses(target string, tech techutils.Technology, licenses []services.License) (err error) { - return tc.simpleJsonConvertor.ParseLicenses(target, tech, licenses) +func (tc *CmdResultsTableConverter) ParseLicenses(target results.ScanTarget, licenses []services.License) (err error) { + return tc.simpleJsonConvertor.ParseLicenses(target, licenses) } -func (tc *CmdResultsTableConverter) ParseSecrets(target string, secrets ...*sarif.Run) (err error) { +func (tc *CmdResultsTableConverter) ParseSecrets(target results.ScanTarget, secrets ...*sarif.Run) (err error) { return tc.simpleJsonConvertor.ParseSecrets(target, secrets...) } -func (tc *CmdResultsTableConverter) ParseIacs(target string, iacs ...*sarif.Run) (err error) { +func (tc *CmdResultsTableConverter) ParseIacs(target results.ScanTarget, iacs ...*sarif.Run) (err error) { return tc.simpleJsonConvertor.ParseIacs(target, iacs...) } -func (tc *CmdResultsTableConverter) ParseSast(target string, sast ...*sarif.Run) (err error) { +func (tc *CmdResultsTableConverter) ParseSast(target results.ScanTarget, sast ...*sarif.Run) (err error) { return tc.simpleJsonConvertor.ParseSast(target, sast...) } diff --git a/utils/results/output/resultwriter.go b/utils/results/output/resultwriter.go index 976b1c1d..5d0122dc 100644 --- a/utils/results/output/resultwriter.go +++ b/utils/results/output/resultwriter.go @@ -1,6 +1,7 @@ package output import ( + "fmt" "os" "slices" @@ -8,7 +9,6 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" - "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/results/conversion" @@ -16,6 +16,7 @@ import ( "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "github.com/jfrog/jfrog-client-go/utils/log" "github.com/jfrog/jfrog-client-go/xray/services" + "github.com/owenrumney/go-sarif/v2/sarif" ) type ResultsWriter struct { @@ -25,6 +26,8 @@ type ResultsWriter struct { format format.OutputFormat // IncludeVulnerabilities If true, include all vulnerabilities as part of the output. Else, include violations only. includeVulnerabilities bool + // If true, will print violation results. + hasViolationContext bool // IncludeLicenses If true, also include license violations as part of the output. includeLicenses bool // IsMultipleRoots multipleRoots is set to true, in case the given results array contains (or may contain) results of several projects (like in binary scan). @@ -63,6 +66,11 @@ func (rw *ResultsWriter) SetSubScansPreformed(subScansPreformed []utils.SubScanT return rw } +func (rw *ResultsWriter) SetHasViolationContext(hasViolationContext bool) *ResultsWriter { + rw.hasViolationContext = hasViolationContext + return rw +} + func (rw *ResultsWriter) SetIncludeVulnerabilities(includeVulnerabilities bool) *ResultsWriter { rw.includeVulnerabilities = includeVulnerabilities return rw @@ -110,7 +118,7 @@ func shouldPrintTable(requestedScans []utils.SubScanType, subScan utils.SubScanT // PrintScanResults prints the scan results in the specified format. // Note that errors are printed only with SimpleJson format. func (rw *ResultsWriter) PrintScanResults() error { - if rw.commandResults.GetErrors() != nil && !rw.commandResults.HasInformation() { + if rw.commandResults.GetErrors() != nil { // Don't print if there are no results and only errors. return nil } @@ -118,17 +126,22 @@ func (rw *ResultsWriter) PrintScanResults() error { case format.Table: return rw.printTables() case format.SimpleJson: + // Helper for Debugging purposes, print the raw results to the log + if err := rw.printOrSaveRawResults(false); err != nil { + return err + } simpleJson, err := rw.createResultsConvertor(false).ConvertToSimpleJson(rw.commandResults) if err != nil { return err } return PrintJson(simpleJson) case format.Json: - if rw.printExtended { - return PrintJson(rw.commandResults) - } return PrintJson(rw.commandResults.GetScaScansXrayResults()) case format.Sarif: + // Helper for Debugging purposes, print the raw results to the log + if err := rw.printOrSaveRawResults(false); err != nil { + return err + } return rw.printSarif() } return nil @@ -136,11 +149,11 @@ func (rw *ResultsWriter) PrintScanResults() error { func (rw *ResultsWriter) createResultsConvertor(pretty bool) *conversion.CommandResultsConvertor { return conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{ - IsMultipleRoots: rw.isMultipleRoots, - IncludeLicenses: rw.includeLicenses, - IncludeVulnerabilities: rw.includeVulnerabilities, - Pretty: pretty, - AllowResultsWithoutLocations: true, + IsMultipleRoots: rw.isMultipleRoots, + IncludeLicenses: rw.includeLicenses, + IncludeVulnerabilities: rw.includeVulnerabilities, + HasViolationContext: rw.hasViolationContext, + Pretty: pretty, }) } @@ -149,7 +162,7 @@ func (rw *ResultsWriter) printSarif() error { if err != nil { return err } - sarifFile, err := sarifutils.ConvertSarifReportToString(sarifContent) + sarifFile, err := WriteSarifResultsAsString(sarifContent, false) if err != nil { return err } @@ -166,29 +179,52 @@ func PrintJson(output interface{}) (err error) { return nil } -func (rw *ResultsWriter) printTables() (err error) { - tableContent, err := rw.createResultsConvertor(isPrettyOutputSupported()).ConvertToTable(rw.commandResults) - if err != nil { +// If "CI" env var is true, print raw JSON of the results. Otherwise, save it as a file and print a link to it. +// If printMsg is true, print it to the console. Otherwise, print the message to the log. +func (rw *ResultsWriter) printOrSaveRawResults(printMsg bool) (err error) { + if !rw.commandResults.HasInformation() { + log.Debug("No information to print") return } - printMessages(rw.messages) - if rw.commandResults.HasInformation() { + if printMsg && !utils.IsCI() { + // Save the results to a file and print a link to it. var resultsPath string if resultsPath, err = writeJsonResults(rw.commandResults); err != nil { return } printMessage(coreutils.PrintTitle("The full scan results are available here: ") + coreutils.PrintLink(resultsPath)) + return + } + // Print the raw results to console. + var msg string + if msg, err = utils.GetAsJsonString(rw.commandResults, false, true); err != nil { + return + } + log.Debug(fmt.Sprintf("Raw scan results:\n%s", msg)) + return +} + +func (rw *ResultsWriter) printTables() (err error) { + tableContent, err := rw.createResultsConvertor(isPrettyOutputSupported()).ConvertToTable(rw.commandResults) + if err != nil { + return + } + printMessages(rw.messages) + if err = rw.printOrSaveRawResults(true); err != nil { + return } log.Output() if shouldPrintTable(rw.subScansPreformed, utils.ScaScan, rw.scanType) { - if rw.includeVulnerabilities { - err = PrintVulnerabilitiesTable(tableContent, rw.scanType, len(rw.commandResults.GetTechnologies()) > 0, rw.printExtended) - } else { - err = PrintViolationsTable(tableContent, rw.scanType, rw.printExtended) + if rw.hasViolationContext { + if err = PrintViolationsTable(tableContent, rw.scanType, rw.printExtended); err != nil { + return + } } - if err != nil { - return + if rw.includeVulnerabilities { + if err = PrintVulnerabilitiesTable(tableContent, rw.scanType, len(rw.commandResults.GetTechnologies()) > 0, rw.printExtended); err != nil { + return + } } if rw.includeLicenses { if err = PrintLicensesTable(tableContent, rw.printExtended, rw.scanType); err != nil { @@ -315,3 +351,7 @@ func writeJsonResults(results *results.SecurityCommandResults) (resultsPath stri resultsPath = out.Name() return } + +func WriteSarifResultsAsString(report *sarif.Report, escape bool) (sarifStr string, err error) { + return utils.GetAsJsonString(report, escape, true) +} diff --git a/utils/results/output/securityJobSummary.go b/utils/results/output/securityJobSummary.go index 6471591e..6ae93218 100644 --- a/utils/results/output/securityJobSummary.go +++ b/utils/results/output/securityJobSummary.go @@ -14,8 +14,10 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/commandsummary" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/resources" + "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/results/conversion" @@ -67,36 +69,44 @@ func getStatusIcon(failed bool) string { type SecurityJobSummary struct{} -func newResultSummary(cmdResults *Results, cmdType CommandType, serverDetails *config.ServerDetails, vulnerabilitiesRequested, violationsRequested bool) (summary ScanCommandResultSummary) { - summary.ResultType = cmdType +func newResultSummary(cmdResults *results.SecurityCommandResults, serverDetails *config.ServerDetails, vulnerabilitiesRequested, violationsRequested bool) (summary ScanCommandResultSummary, err error) { + summary.ResultType = cmdResults.CmdType summary.Args = &ResultSummaryArgs{BaseJfrogUrl: serverDetails.Url} - summary.Summary = ToSummary(cmdResults, vulnerabilitiesRequested, violationsRequested) + summary.Summary, err = conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{ + IncludeVulnerabilities: vulnerabilitiesRequested, + HasViolationContext: violationsRequested, + Pretty: true, + }).ConvertToSummary(cmdResults) return } -func NewBuildScanSummary(cmdResults *Results, serverDetails *config.ServerDetails, vulnerabilitiesRequested, violationsRequested bool, buildName, buildNumber string) (summary ScanCommandResultSummary) { - summary = newResultSummary(cmdResults, Build, serverDetails, vulnerabilitiesRequested, violationsRequested) +func NewBuildScanSummary(cmdResults *results.SecurityCommandResults, serverDetails *config.ServerDetails, vulnerabilitiesRequested, violationsRequested bool, buildName, buildNumber string) (summary ScanCommandResultSummary, err error) { + if summary, err = newResultSummary(cmdResults, serverDetails, vulnerabilitiesRequested, violationsRequested); err != nil { + return + } summary.Args.BuildName = buildName summary.Args.BuildNumbers = []string{buildNumber} return } -func NewDockerScanSummary(cmdResults *Results, serverDetails *config.ServerDetails, vulnerabilitiesRequested, violationsRequested bool, dockerImage string) (summary ScanCommandResultSummary) { - summary = newResultSummary(cmdResults, DockerImage, serverDetails, vulnerabilitiesRequested, violationsRequested) +func NewDockerScanSummary(cmdResults *results.SecurityCommandResults, serverDetails *config.ServerDetails, vulnerabilitiesRequested, violationsRequested bool, dockerImage string) (summary ScanCommandResultSummary, err error) { + if summary, err = newResultSummary(cmdResults, serverDetails, vulnerabilitiesRequested, violationsRequested); err != nil { + return + } summary.Args.DockerImage = dockerImage return } -func NewBinaryScanSummary(cmdResults *Results, serverDetails *config.ServerDetails, vulnerabilitiesRequested, violationsRequested bool) (summary ScanCommandResultSummary) { - return newResultSummary(cmdResults, Binary, serverDetails, vulnerabilitiesRequested, violationsRequested) +func NewBinaryScanSummary(cmdResults *results.SecurityCommandResults, serverDetails *config.ServerDetails, vulnerabilitiesRequested, violationsRequested bool) (summary ScanCommandResultSummary, err error) { + return newResultSummary(cmdResults, serverDetails, vulnerabilitiesRequested, violationsRequested) } -func NewAuditScanSummary(cmdResults *Results, serverDetails *config.ServerDetails, vulnerabilitiesRequested, violationsRequested bool) (summary ScanCommandResultSummary) { - return newResultSummary(cmdResults, SourceCode, serverDetails, vulnerabilitiesRequested, violationsRequested) +func NewAuditScanSummary(cmdResults *results.SecurityCommandResults, serverDetails *config.ServerDetails, vulnerabilitiesRequested, violationsRequested bool) (summary ScanCommandResultSummary, err error) { + return newResultSummary(cmdResults, serverDetails, vulnerabilitiesRequested, violationsRequested) } func NewCurationSummary(cmdResult formats.ResultsSummary) (summary ScanCommandResultSummary) { - summary.ResultType = Curation + summary.ResultType = utils.Curation summary.Summary = cmdResult return } @@ -140,14 +150,14 @@ func (rsa ResultSummaryArgs) ToArgs(index commandsummary.Index) (args []string) } type ScanCommandResultSummary struct { - ResultType CommandType `json:"resultType"` + ResultType utils.CommandType `json:"resultType"` Args *ResultSummaryArgs `json:"args,omitempty"` Summary formats.ResultsSummary `json:"summary"` } // Manage the job summary for security commands -func SecurityCommandsJobSummary() (js *commandsummary.CommandSummary, err error) { - return commandsummary.New(&SecurityCommandsSummary{}, "security") +func NewSecurityJobSummary() (js *commandsummary.CommandSummary, err error) { + return commandsummary.New(&SecurityJobSummary{}, "security") } func getRecordManager() (manager *commandsummary.CommandSummary, err error) { @@ -174,7 +184,8 @@ func RecordSecurityCommandSummary(content ScanCommandResultSummary) (err error) return manager.Record(content) } -func RecordSarifOutput(cmdResults *Results) (err error) { +func RecordSarifOutput(cmdResults *results.SecurityCommandResults, includeVulnerabilities, hasViolationContext bool) (err error) { + // Verify if we should record the results manager, err := getRecordManager() if err != nil || manager == nil { return @@ -184,11 +195,17 @@ func RecordSarifOutput(cmdResults *Results) (err error) { log.Info("Results can be uploaded to Github security tab automatically by upgrading your JFrog subscription.") return } - sarifReport, err := GenerateSarifReportFromResults(cmdResults, true, false, nil) + // Convert the results to SARIF format + sarifReport, err := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{ + IncludeVulnerabilities: includeVulnerabilities, + HasViolationContext: hasViolationContext, + Pretty: true, + }).ConvertToSarif(cmdResults) if err != nil { return err } - out, err := JSONMarshalNotEscaped(sarifReport) + // Record the SARIF report + out, err := utils.GetAsJsonBytes(sarifReport, false, false) if err != nil { return errorutils.CheckError(err) } @@ -215,7 +232,7 @@ func CombineSarifOutputFiles(dataFilePaths []string) (data []byte, err error) { if err != nil { return } - return JSONMarshalNotEscaped(combined) + return utils.GetAsJsonBytes(combined, false, false) } func loadSarifReport(dataFilePath string) (report *sarif.Report, err error) { @@ -241,15 +258,15 @@ func updateSummaryNamesToRelativePath(summary *formats.ResultsSummary, wd string } } -func getDataIndexFromCommandType(cmdType CommandType) commandsummary.Index { +func getDataIndexFromCommandType(cmdType utils.CommandType) commandsummary.Index { switch cmdType { - case Build: + case utils.Build: return commandsummary.BuildScan - case Binary: + case utils.Binary: return commandsummary.BinariesScan - case SourceCode: + case utils.SourceCode: return commandsummary.BinariesScan - case DockerImage: + case utils.DockerImage: return commandsummary.DockerScan } // No index for the section @@ -270,11 +287,11 @@ func recordIndexData(manager *commandsummary.CommandSummary, content ScanCommand return } -func newScanCommandResultSummary(resultType CommandType, args *ResultSummaryArgs, scans ...formats.ScanSummary) ScanCommandResultSummary { +func newScanCommandResultSummary(resultType utils.CommandType, args *ResultSummaryArgs, scans ...formats.ScanSummary) ScanCommandResultSummary { return ScanCommandResultSummary{ResultType: resultType, Args: args, Summary: formats.ResultsSummary{Scans: scans}} } -func loadContent(dataFiles []string, filterSections ...CommandType) ([]formats.ResultsSummary, ResultSummaryArgs, error) { +func loadContent(dataFiles []string, filterSections ...utils.CommandType) ([]formats.ResultsSummary, ResultSummaryArgs, error) { data := []formats.ResultsSummary{} args := ResultSummaryArgs{} for _, dataFilePath := range dataFiles { @@ -327,7 +344,7 @@ func (js *SecurityJobSummary) GetNonScannedResult() (generator EmptyMarkdownGene // Generate the Security section (Curation) func (js *SecurityJobSummary) GenerateMarkdownFromFiles(dataFilePaths []string) (markdown string, err error) { - curationData, _, err := loadContent(dataFilePaths, Curation) + curationData, _, err := loadContent(dataFilePaths, utils.Curation) if err != nil { return } diff --git a/utils/results/output/securityJobSummary_test.go b/utils/results/output/securityJobSummary_test.go index 3f0f56ee..bca93284 100644 --- a/utils/results/output/securityJobSummary_test.go +++ b/utils/results/output/securityJobSummary_test.go @@ -9,15 +9,15 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/commandsummary" coreTests "github.com/jfrog/jfrog-cli-core/v2/utils/tests" - "github.com/jfrog/jfrog-cli-security/formats" + "github.com/jfrog/jfrog-cli-security/utils" + "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/validations" "github.com/stretchr/testify/assert" ) var ( - summaryExpectedContentDir = filepath.Join("..", "tests", "testdata", "other", "jobSummary") - testPlatformUrl = "https://test-platform-url.jfrog.io/" - testMoreInfoUrl = "https://test-more-info-url.jfrog.io/" + summaryExpectedContentDir = filepath.Join("..", "..", "..", "tests", "testdata", "output", "jobSummary") securityScaResults = formats.ResultSummary{ "Critical": map[string]int{jasutils.Applicable.String(): 2, jasutils.NotApplicable.String(): 2, jasutils.NotCovered.String(): 3, jasutils.ApplicabilityUndetermined.String(): 1}, @@ -27,8 +27,8 @@ var ( } violationResults = formats.ScanResultSummary{ ScaResults: &formats.ScaScanResultSummary{ - ScanIds: []string{TestScaScanId}, - MoreInfoUrls: []string{testMoreInfoUrl}, + ScanIds: []string{validations.TestScaScanId}, + MoreInfoUrls: []string{validations.TestMoreInfoUrl}, Security: securityScaResults, License: formats.ResultSummary{"High": map[string]int{formats.NoStatus: 1}}, OperationalRisk: formats.ResultSummary{"Low": map[string]int{formats.NoStatus: 2}}, @@ -39,9 +39,9 @@ var ( func TestSaveLoadData(t *testing.T) { testDockerScanSummary := ScanCommandResultSummary{ - ResultType: DockerImage, + ResultType: utils.DockerImage, Args: &ResultSummaryArgs{ - BaseJfrogUrl: testPlatformUrl, + BaseJfrogUrl: validations.TestPlatformUrl, DockerImage: "dockerImage:version", }, Summary: formats.ResultsSummary{ @@ -50,8 +50,8 @@ func TestSaveLoadData(t *testing.T) { Target: filepath.Join("path", "to", "image.tar"), Vulnerabilities: &formats.ScanResultSummary{ ScaResults: &formats.ScaScanResultSummary{ - ScanIds: []string{TestScaScanId}, - MoreInfoUrls: []string{testMoreInfoUrl}, + ScanIds: []string{validations.TestScaScanId}, + MoreInfoUrls: []string{validations.TestMoreInfoUrl}, Security: securityScaResults, }, }, @@ -64,9 +64,9 @@ func TestSaveLoadData(t *testing.T) { }, } testBinaryScanSummary := ScanCommandResultSummary{ - ResultType: Binary, + ResultType: utils.Binary, Args: &ResultSummaryArgs{ - BaseJfrogUrl: testPlatformUrl, + BaseJfrogUrl: validations.TestPlatformUrl, }, Summary: formats.ResultsSummary{ Scans: []formats.ScanSummary{ @@ -91,9 +91,9 @@ func TestSaveLoadData(t *testing.T) { }, } testBuildScanSummary := ScanCommandResultSummary{ - ResultType: Build, + ResultType: utils.Build, Args: &ResultSummaryArgs{ - BaseJfrogUrl: testPlatformUrl, + BaseJfrogUrl: validations.TestPlatformUrl, BuildName: "build-name", BuildNumbers: []string{"build-number"}, }, @@ -110,7 +110,7 @@ func TestSaveLoadData(t *testing.T) { }, } testCurationSummary := ScanCommandResultSummary{ - ResultType: Curation, + ResultType: utils.Curation, Summary: formats.ResultsSummary{ Scans: []formats.ScanSummary{ { @@ -133,7 +133,7 @@ func TestSaveLoadData(t *testing.T) { testCases := []struct { name string content []ScanCommandResultSummary - filterSections []CommandType + filterSections []utils.CommandType expectedArgs ResultSummaryArgs expectedContent []formats.ResultsSummary }{ @@ -147,7 +147,7 @@ func TestSaveLoadData(t *testing.T) { name: "Multiple scans", content: []ScanCommandResultSummary{testDockerScanSummary, testBinaryScanSummary, testBuildScanSummary}, expectedArgs: ResultSummaryArgs{ - BaseJfrogUrl: testPlatformUrl, + BaseJfrogUrl: validations.TestPlatformUrl, DockerImage: "dockerImage:version", BuildName: "build-name", BuildNumbers: []string{"build-number"}, @@ -156,7 +156,7 @@ func TestSaveLoadData(t *testing.T) { }, { name: "Multiple scans with filter", - filterSections: []CommandType{Curation}, + filterSections: []utils.CommandType{utils.Curation}, content: []ScanCommandResultSummary{testDockerScanSummary, testBinaryScanSummary, testBuildScanSummary, testCurationSummary}, expectedContent: []formats.ResultsSummary{testCurationSummary.Summary}, }, @@ -169,7 +169,7 @@ func TestSaveLoadData(t *testing.T) { // Save the data for i := range testCase.content { updateSummaryNamesToRelativePath(&testCase.content[i].Summary, tempDir) - data, err := JSONMarshalNotEscaped(&testCase.content[i]) + data, err := utils.GetAsJsonBytes(&testCase.content[i], false, false) assert.NoError(t, err) dataFilePath := filepath.Join(tempDir, fmt.Sprintf("data_%s_%d.json", testCase.name, i)) assert.NoError(t, os.WriteFile(dataFilePath, data, 0644)) @@ -245,11 +245,11 @@ func TestGenerateJobSummaryMarkdown(t *testing.T) { name: "No vulnerabilities", index: commandsummary.BinariesScan, expectedContentPath: filepath.Join(summaryExpectedContentDir, "no_vulnerabilities.md"), - args: &ResultSummaryArgs{BaseJfrogUrl: testPlatformUrl}, + args: &ResultSummaryArgs{BaseJfrogUrl: validations.TestPlatformUrl}, content: []formats.ResultsSummary{{ Scans: []formats.ScanSummary{{ Target: filepath.Join(wd, "binary-name"), - Vulnerabilities: &formats.ScanResultSummary{ScaResults: &formats.ScaScanResultSummary{ScanIds: []string{TestScaScanId}, MoreInfoUrls: []string{testMoreInfoUrl}}}, + Vulnerabilities: &formats.ScanResultSummary{ScaResults: &formats.ScaScanResultSummary{ScanIds: []string{validations.TestScaScanId}, MoreInfoUrls: []string{validations.TestMoreInfoUrl}}}, }}, }}, }, @@ -258,11 +258,11 @@ func TestGenerateJobSummaryMarkdown(t *testing.T) { index: commandsummary.BinariesScan, violations: true, expectedContentPath: filepath.Join(summaryExpectedContentDir, "violations_not_defined.md"), - args: &ResultSummaryArgs{BaseJfrogUrl: testPlatformUrl}, + args: &ResultSummaryArgs{BaseJfrogUrl: validations.TestPlatformUrl}, content: []formats.ResultsSummary{{ Scans: []formats.ScanSummary{{ Target: filepath.Join(wd, "binary-name"), - Vulnerabilities: &formats.ScanResultSummary{ScaResults: &formats.ScaScanResultSummary{ScanIds: []string{TestScaScanId}}}, + Vulnerabilities: &formats.ScanResultSummary{ScaResults: &formats.ScaScanResultSummary{ScanIds: []string{validations.TestScaScanId}}}, }}, }}, }, @@ -271,13 +271,13 @@ func TestGenerateJobSummaryMarkdown(t *testing.T) { index: commandsummary.BinariesScan, violations: true, expectedContentPath: filepath.Join(summaryExpectedContentDir, "no_violations.md"), - args: &ResultSummaryArgs{BaseJfrogUrl: testPlatformUrl}, + args: &ResultSummaryArgs{BaseJfrogUrl: validations.TestPlatformUrl}, content: []formats.ResultsSummary{{ Scans: []formats.ScanSummary{{ Target: filepath.Join(wd, "other-binary-name"), Violations: &formats.ScanViolationsSummary{ Watches: []string{}, - ScanResultSummary: formats.ScanResultSummary{ScaResults: &formats.ScaScanResultSummary{ScanIds: []string{TestScaScanId}, MoreInfoUrls: []string{testMoreInfoUrl}}}, + ScanResultSummary: formats.ScanResultSummary{ScaResults: &formats.ScaScanResultSummary{ScanIds: []string{validations.TestScaScanId}, MoreInfoUrls: []string{validations.TestMoreInfoUrl}}}, }, }}, }}, @@ -286,13 +286,13 @@ func TestGenerateJobSummaryMarkdown(t *testing.T) { name: "Build Scan Vulnerabilities", index: commandsummary.BuildScan, expectedContentPath: filepath.Join(summaryExpectedContentDir, "build_scan_vulnerabilities.md"), - args: &ResultSummaryArgs{BaseJfrogUrl: testPlatformUrl, BuildName: "build-name", BuildNumbers: []string{"build-number"}}, + args: &ResultSummaryArgs{BaseJfrogUrl: validations.TestPlatformUrl, BuildName: "build-name", BuildNumbers: []string{"build-number"}}, content: []formats.ResultsSummary{{ Scans: []formats.ScanSummary{{ Target: "build-name (build-number)", Vulnerabilities: &formats.ScanResultSummary{ScaResults: &formats.ScaScanResultSummary{ - ScanIds: []string{TestScaScanId}, - MoreInfoUrls: []string{testMoreInfoUrl}, + ScanIds: []string{validations.TestScaScanId}, + MoreInfoUrls: []string{validations.TestMoreInfoUrl}, Security: formats.ResultSummary{"High": map[string]int{formats.NoStatus: 3}, "Medium": map[string]int{formats.NoStatus: 1}, "Unknown": map[string]int{formats.NoStatus: 20}}, }}, }}, @@ -302,12 +302,12 @@ func TestGenerateJobSummaryMarkdown(t *testing.T) { name: "Binary Scan Vulnerabilities", index: commandsummary.BinariesScan, expectedContentPath: filepath.Join(summaryExpectedContentDir, "binary_vulnerabilities.md"), - args: &ResultSummaryArgs{BaseJfrogUrl: testPlatformUrl}, + args: &ResultSummaryArgs{BaseJfrogUrl: validations.TestPlatformUrl}, content: []formats.ResultsSummary{{ Scans: []formats.ScanSummary{{ Target: filepath.Join(wd, "binary-with-issues"), Vulnerabilities: &formats.ScanResultSummary{ScaResults: &formats.ScaScanResultSummary{ - ScanIds: []string{TestScaScanId, "scan-id-2"}, + ScanIds: []string{validations.TestScaScanId, "scan-id-2"}, MoreInfoUrls: []string{""}, Security: formats.ResultSummary{"Critical": map[string]int{formats.NoStatus: 33}, "Low": map[string]int{formats.NoStatus: 11}}, }}, @@ -318,13 +318,13 @@ func TestGenerateJobSummaryMarkdown(t *testing.T) { name: "Docker Scan Vulnerabilities", index: commandsummary.DockerScan, expectedContentPath: filepath.Join(summaryExpectedContentDir, "docker_vulnerabilities.md"), - args: &ResultSummaryArgs{BaseJfrogUrl: testPlatformUrl, DockerImage: "dockerImage:version"}, + args: &ResultSummaryArgs{BaseJfrogUrl: validations.TestPlatformUrl, DockerImage: "dockerImage:version"}, content: []formats.ResultsSummary{{ Scans: []formats.ScanSummary{{ Target: filepath.Join(wd, "image.tar"), Vulnerabilities: &formats.ScanResultSummary{ ScaResults: &formats.ScaScanResultSummary{ - ScanIds: []string{TestScaScanId}, + ScanIds: []string{validations.TestScaScanId}, MoreInfoUrls: []string{""}, Security: securityScaResults, }, @@ -340,7 +340,7 @@ func TestGenerateJobSummaryMarkdown(t *testing.T) { index: commandsummary.DockerScan, violations: true, expectedContentPath: filepath.Join(summaryExpectedContentDir, "violations.md"), - args: &ResultSummaryArgs{BaseJfrogUrl: testPlatformUrl, DockerImage: "dockerImage:version"}, + args: &ResultSummaryArgs{BaseJfrogUrl: validations.TestPlatformUrl, DockerImage: "dockerImage:version"}, content: []formats.ResultsSummary{{ Scans: []formats.ScanSummary{{ Target: filepath.Join(wd, "image.tar"), @@ -357,7 +357,7 @@ func TestGenerateJobSummaryMarkdown(t *testing.T) { violations: true, NoExtendedView: true, expectedContentPath: filepath.Join(summaryExpectedContentDir, "violations_not_extended_view.md"), - args: &ResultSummaryArgs{BaseJfrogUrl: testPlatformUrl, DockerImage: "dockerImage:version"}, + args: &ResultSummaryArgs{BaseJfrogUrl: validations.TestPlatformUrl, DockerImage: "dockerImage:version"}, content: []formats.ResultsSummary{{ Scans: []formats.ScanSummary{{ Target: filepath.Join(wd, "image.tar"), @@ -371,7 +371,7 @@ func TestGenerateJobSummaryMarkdown(t *testing.T) { { name: "Vulnerability not requested", index: commandsummary.DockerScan, - args: &ResultSummaryArgs{BaseJfrogUrl: testPlatformUrl, DockerImage: "dockerImage:version"}, + args: &ResultSummaryArgs{BaseJfrogUrl: validations.TestPlatformUrl, DockerImage: "dockerImage:version"}, content: []formats.ResultsSummary{{ Scans: []formats.ScanSummary{{ Target: filepath.Join(wd, "image.tar"), @@ -435,29 +435,4 @@ func getOutputFromFile(t *testing.T, path string) string { content, err := os.ReadFile(path) assert.NoError(t, err) return strings.ReplaceAll(string(content), "\r\n", "\n") - return strings.ReplaceAll(filepath.FromSlash(strings.ReplaceAll(string(content), "\r\n", "\n")), "<"+string(filepath.Separator), " 0 { - return coreutils.PrintTable(formats.ConvertToOperationalRiskViolationScanTableRow(operationalRiskViolationsRows), "Operational Risk Violations", "No operational risk violations were found", printExtended) - } - } else { - err = coreutils.PrintTable(formats.ConvertToVulnerabilityTableRow(securityViolationsRows), "Security Violations", "No security violations were found", printExtended) - if err != nil { - return err - } - err = coreutils.PrintTable(formats.ConvertToLicenseViolationTableRow(licenseViolationsRows), "License Compliance Violations", "No license compliance violations were found", printExtended) - if err != nil { - return err - } - if len(operationalRiskViolationsRows) > 0 { - return coreutils.PrintTable(formats.ConvertToOperationalRiskViolationTableRow(operationalRiskViolationsRows), "Operational Risk Violations", "No operational risk violations were found", printExtended) - } - } - return nil -} - -// Prepare violations for all non-table formats (without style or emoji) -func PrepareViolations(violations []services.Violation, results *Results, multipleRoots, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, []formats.LicenseRow, []formats.OperationalRiskViolationRow, error) { - return prepareViolations(violations, results, multipleRoots, false, simplifiedOutput) -} - -func prepareViolations(violations []services.Violation, results *Results, multipleRoots, isTable, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, []formats.LicenseRow, []formats.OperationalRiskViolationRow, error) { - if simplifiedOutput { - violations = simplifyViolations(violations, multipleRoots) - } - var securityViolationsRows []formats.VulnerabilityOrViolationRow - var licenseViolationsRows []formats.LicenseRow - var operationalRiskViolationsRows []formats.OperationalRiskViolationRow - for _, violation := range violations { - impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, fixedVersions, components, impactPaths, err := splitComponents(violation.Components) - if err != nil { - return nil, nil, nil, err - } - switch violation.ViolationType { - case ViolationTypeSecurity.String(): - cves := convertCves(violation.Cves) - if results.ExtendedScanResults.EntitledForJas { - for i := range cves { - cves[i].Applicability = getCveApplicabilityField(cves[i].Id, results.ExtendedScanResults.ApplicabilityScanResults, violation.Components) - } - } - applicabilityStatus := getApplicableCveStatus(results.ExtendedScanResults.EntitledForJas, results.ExtendedScanResults.ApplicabilityScanResults, cves) - currSeverity, err := severityutils.ParseSeverity(violation.Severity, false) - if err != nil { - return nil, nil, nil, err - } - jfrogResearchInfo := convertJfrogResearchInformation(violation.ExtendedInformation) - for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { - securityViolationsRows = append(securityViolationsRows, - formats.VulnerabilityOrViolationRow{ - Summary: violation.Summary, - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: severityutils.GetAsDetails(currSeverity, applicabilityStatus, isTable), - ImpactedDependencyName: impactedPackagesNames[compIndex], - ImpactedDependencyVersion: impactedPackagesVersions[compIndex], - ImpactedDependencyType: impactedPackagesTypes[compIndex], - Components: components[compIndex], - }, - FixedVersions: fixedVersions[compIndex], - Cves: cves, - IssueId: violation.IssueId, - References: violation.References, - JfrogResearchInformation: jfrogResearchInfo, - ImpactPaths: impactPaths[compIndex], - Technology: techutils.Technology(violation.Technology), - Applicable: printApplicabilityCveValue(applicabilityStatus, isTable), - }, - ) - } - case ViolationTypeLicense.String(): - currSeverity, err := severityutils.ParseSeverity(violation.Severity, false) - if err != nil { - return nil, nil, nil, err - } - for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { - licenseViolationsRows = append(licenseViolationsRows, - formats.LicenseRow{ - LicenseKey: violation.LicenseKey, - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: severityutils.GetAsDetails(currSeverity, jasutils.NotScanned, isTable), - ImpactedDependencyName: impactedPackagesNames[compIndex], - ImpactedDependencyVersion: impactedPackagesVersions[compIndex], - ImpactedDependencyType: impactedPackagesTypes[compIndex], - Components: components[compIndex], - }, - }, - ) - } - case ViolationTypeOperationalRisk.String(): - currSeverity, err := severityutils.ParseSeverity(violation.Severity, false) - if err != nil { - return nil, nil, nil, err - } - violationOpRiskData := getOperationalRiskViolationReadableData(violation) - for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { - operationalRiskViolationsRow := &formats.OperationalRiskViolationRow{ - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: severityutils.GetAsDetails(currSeverity, jasutils.NotScanned, isTable), - ImpactedDependencyName: impactedPackagesNames[compIndex], - ImpactedDependencyVersion: impactedPackagesVersions[compIndex], - ImpactedDependencyType: impactedPackagesTypes[compIndex], - Components: components[compIndex], - }, - IsEol: violationOpRiskData.isEol, - Cadence: violationOpRiskData.cadence, - Commits: violationOpRiskData.commits, - Committers: violationOpRiskData.committers, - NewerVersions: violationOpRiskData.newerVersions, - LatestVersion: violationOpRiskData.latestVersion, - RiskReason: violationOpRiskData.riskReason, - EolMessage: violationOpRiskData.eolMessage, - } - operationalRiskViolationsRows = append(operationalRiskViolationsRows, *operationalRiskViolationsRow) - } - default: - // Unsupported type, ignore - } - } - - // Sort the rows by severity and whether the row contains fixed versions - sortVulnerabilityOrViolationRows(securityViolationsRows) - sort.Slice(licenseViolationsRows, func(i, j int) bool { - return licenseViolationsRows[i].SeverityNumValue > licenseViolationsRows[j].SeverityNumValue - }) - sort.Slice(operationalRiskViolationsRows, func(i, j int) bool { - return operationalRiskViolationsRows[i].SeverityNumValue > operationalRiskViolationsRows[j].SeverityNumValue - }) - - return securityViolationsRows, licenseViolationsRows, operationalRiskViolationsRows, nil -} - -// PrintVulnerabilitiesTable prints the vulnerabilities in a table. -// Set multipleRoots to true in case the given vulnerabilities array contains (or may contain) results of several projects or files (like in binary scan). -// In case multipleRoots is true, the field Component will show the root of each impact path, otherwise it will show the root's child. -// Set printExtended to true to print fields with 'extended' tag. -// If the scan argument is set to true, print the scan tables. -func PrintVulnerabilitiesTable(vulnerabilities []services.Vulnerability, results *Results, multipleRoots, printExtended bool, scanType CommandType) error { - vulnerabilitiesRows, err := prepareVulnerabilities(vulnerabilities, results, multipleRoots, true, true) - if err != nil { - return err - } - - if scanType.IsTargetBinary() { - return coreutils.PrintTable(formats.ConvertToVulnerabilityScanTableRow(vulnerabilitiesRows), "Vulnerable Components", "✨ No vulnerable components were found ✨", printExtended) - } - var emptyTableMessage string - if len(results.ScaResults) > 0 { - emptyTableMessage = "✨ No vulnerable dependencies were found ✨" - } else { - emptyTableMessage = coreutils.PrintYellow("🔧 Couldn't determine a package manager or build tool used by this project 🔧") - } - return coreutils.PrintTable(formats.ConvertToVulnerabilityTableRow(vulnerabilitiesRows), "Vulnerable Dependencies", emptyTableMessage, printExtended) -} - -// Prepare vulnerabilities for all non-table formats (without style or emoji) -func PrepareVulnerabilities(vulnerabilities []services.Vulnerability, results *Results, multipleRoots, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, error) { - return prepareVulnerabilities(vulnerabilities, results, multipleRoots, false, simplifiedOutput) -} - -func prepareVulnerabilities(vulnerabilities []services.Vulnerability, results *Results, multipleRoots, isTable, simplifiedOutput bool) ([]formats.VulnerabilityOrViolationRow, error) { - if simplifiedOutput { - vulnerabilities = simplifyVulnerabilities(vulnerabilities, multipleRoots) - } - var vulnerabilitiesRows []formats.VulnerabilityOrViolationRow - for _, vulnerability := range vulnerabilities { - impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, fixedVersions, components, impactPaths, err := splitComponents(vulnerability.Components) - if err != nil { - return nil, err - } - cves := convertCves(vulnerability.Cves) - if results.ExtendedScanResults.EntitledForJas { - for i := range cves { - cves[i].Applicability = getCveApplicabilityField(cves[i].Id, results.ExtendedScanResults.ApplicabilityScanResults, vulnerability.Components) - } - } - applicabilityStatus := getApplicableCveStatus(results.ExtendedScanResults.EntitledForJas, results.ExtendedScanResults.ApplicabilityScanResults, cves) - currSeverity, err := severityutils.ParseSeverity(vulnerability.Severity, false) - if err != nil { - return nil, err - } - jfrogResearchInfo := convertJfrogResearchInformation(vulnerability.ExtendedInformation) - for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { - vulnerabilitiesRows = append(vulnerabilitiesRows, - formats.VulnerabilityOrViolationRow{ - Summary: vulnerability.Summary, - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: severityutils.GetAsDetails(currSeverity, applicabilityStatus, isTable), - ImpactedDependencyName: impactedPackagesNames[compIndex], - ImpactedDependencyVersion: impactedPackagesVersions[compIndex], - ImpactedDependencyType: impactedPackagesTypes[compIndex], - Components: components[compIndex], - }, - FixedVersions: fixedVersions[compIndex], - Cves: cves, - IssueId: vulnerability.IssueId, - References: vulnerability.References, - JfrogResearchInformation: jfrogResearchInfo, - ImpactPaths: impactPaths[compIndex], - Technology: techutils.Technology(vulnerability.Technology), - Applicable: printApplicabilityCveValue(applicabilityStatus, isTable), - }, - ) - } - } - - sortVulnerabilityOrViolationRows(vulnerabilitiesRows) - return vulnerabilitiesRows, nil -} - -// sortVulnerabilityOrViolationRows is sorting in the following order: -// Severity -> Applicability -> JFrog Research Score -> XRAY ID -func sortVulnerabilityOrViolationRows(rows []formats.VulnerabilityOrViolationRow) { - sort.Slice(rows, func(i, j int) bool { - if rows[i].SeverityNumValue != rows[j].SeverityNumValue { - return rows[i].SeverityNumValue > rows[j].SeverityNumValue - } - if rows[i].Applicable != rows[j].Applicable { - return jasutils.ConvertApplicableToScore(rows[i].Applicable) > jasutils.ConvertApplicableToScore(rows[j].Applicable) - } - priorityI := getJfrogResearchPriority(rows[i]) - priorityJ := getJfrogResearchPriority(rows[j]) - if priorityI != priorityJ { - return priorityI > priorityJ - } - return rows[i].IssueId > rows[j].IssueId - }) -} - -// getJfrogResearchPriority returns the score of JFrog Research Severity. -// If there is no such severity will return the normal severity score. -// When vulnerability with JFrog Reasearch to a vulnerability without we'll compare the JFrog Research Severity to the normal severity -func getJfrogResearchPriority(vulnerabilityOrViolation formats.VulnerabilityOrViolationRow) int { - if vulnerabilityOrViolation.JfrogResearchInformation == nil { - return vulnerabilityOrViolation.SeverityNumValue - } - - return vulnerabilityOrViolation.JfrogResearchInformation.SeverityNumValue -} - -// PrintLicensesTable prints the licenses in a table. -// Set multipleRoots to true in case the given licenses array contains (or may contain) results of several projects or files (like in binary scan). -// In case multipleRoots is true, the field Component will show the root of each impact path, otherwise it will show the root's child. -// Set printExtended to true to print fields with 'extended' tag. -// If the scan argument is set to true, print the scan tables. -func PrintLicensesTable(licenses []services.License, printExtended bool, scanType CommandType) error { - licensesRows, err := PrepareLicenses(licenses) - if err != nil { - return err - } - if scanType.IsTargetBinary() { - return coreutils.PrintTable(formats.ConvertToLicenseScanTableRow(licensesRows), "Licenses", "No licenses were found", printExtended) - } - return coreutils.PrintTable(formats.ConvertToLicenseTableRow(licensesRows), "Licenses", "No licenses were found", printExtended) -} - -func PrepareLicenses(licenses []services.License) ([]formats.LicenseRow, error) { - var licensesRows []formats.LicenseRow - for _, license := range licenses { - impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes, _, components, impactPaths, err := splitComponents(license.Components) - if err != nil { - return nil, err - } - for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ { - licensesRows = append(licensesRows, - formats.LicenseRow{ - LicenseKey: license.Key, - ImpactPaths: impactPaths[compIndex], - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - ImpactedDependencyName: impactedPackagesNames[compIndex], - ImpactedDependencyVersion: impactedPackagesVersions[compIndex], - ImpactedDependencyType: impactedPackagesTypes[compIndex], - Components: components[compIndex], - }, - }, - ) - } - } - - return licensesRows, nil -} - -// Prepare secrets for all non-table formats (without style or emoji) -func PrepareSecrets(secrets []*sarif.Run) []formats.SourceCodeRow { - return prepareSecrets(secrets, false) -} - -func prepareSecrets(secrets []*sarif.Run, isTable bool) []formats.SourceCodeRow { - var secretsRows []formats.SourceCodeRow - for _, secretRun := range secrets { - for _, secretResult := range secretRun.Results { - currSeverity, err := severityutils.ParseSeverity(sarifutils.GetResultLevel(secretResult), true) - if err != nil { - log.Warn(fmt.Sprintf("Failed to parse severity `%s` for secret result: %s", sarifutils.GetResultLevel(secretResult), *secretResult.RuleID)) - currSeverity = severityutils.Unknown - } - for _, location := range secretResult.Locations { - secretsRows = append(secretsRows, - formats.SourceCodeRow{ - SeverityDetails: severityutils.GetAsDetails(currSeverity, jasutils.Applicable, isTable), - Finding: sarifutils.GetResultMsgText(secretResult), - Location: formats.Location{ - File: sarifutils.GetRelativeLocationFileName(location, secretRun.Invocations), - StartLine: sarifutils.GetLocationStartLine(location), - StartColumn: sarifutils.GetLocationStartColumn(location), - EndLine: sarifutils.GetLocationEndLine(location), - EndColumn: sarifutils.GetLocationEndColumn(location), - Snippet: sarifutils.GetLocationSnippet(location), - }, - }, - ) - } - } - } - - sort.Slice(secretsRows, func(i, j int) bool { - return secretsRows[i].SeverityNumValue > secretsRows[j].SeverityNumValue - }) - - return secretsRows -} - -func PrintSecretsTable(secrets []*sarif.Run, entitledForSecretsScan bool) error { - if entitledForSecretsScan { - secretsRows := prepareSecrets(secrets, true) - log.Output() - return coreutils.PrintTable(formats.ConvertToSecretsTableRow(secretsRows), "Secret Detection", - "✨ No secrets were found ✨", false) - } - return nil -} - -// Prepare iacs for all non-table formats (without style or emoji) -func PrepareIacs(iacs []*sarif.Run) []formats.SourceCodeRow { - return prepareIacs(iacs, false) -} - -func prepareIacs(iacs []*sarif.Run, isTable bool) []formats.SourceCodeRow { - var iacRows []formats.SourceCodeRow - for _, iacRun := range iacs { - for _, iacResult := range iacRun.Results { - scannerDescription := "" - if rule, err := iacRun.GetRuleById(*iacResult.RuleID); err == nil { - scannerDescription = sarifutils.GetRuleFullDescriptionText(rule) - } - currSeverity, err := severityutils.ParseSeverity(sarifutils.GetResultLevel(iacResult), true) - if err != nil { - log.Warn(fmt.Sprintf("Failed to parse severity `%s` for iac result: %s", sarifutils.GetResultLevel(iacResult), *iacResult.RuleID)) - currSeverity = severityutils.Unknown - } - for _, location := range iacResult.Locations { - iacRows = append(iacRows, - formats.SourceCodeRow{ - SeverityDetails: severityutils.GetAsDetails(currSeverity, jasutils.Applicable, isTable), - Finding: sarifutils.GetResultMsgText(iacResult), - ScannerDescription: scannerDescription, - Location: formats.Location{ - File: sarifutils.GetRelativeLocationFileName(location, iacRun.Invocations), - StartLine: sarifutils.GetLocationStartLine(location), - StartColumn: sarifutils.GetLocationStartColumn(location), - EndLine: sarifutils.GetLocationEndLine(location), - EndColumn: sarifutils.GetLocationEndColumn(location), - Snippet: sarifutils.GetLocationSnippet(location), - }, - }, - ) - } - } - } - - sort.Slice(iacRows, func(i, j int) bool { - return iacRows[i].SeverityNumValue > iacRows[j].SeverityNumValue - }) - - return iacRows -} - -func PrintIacTable(iacs []*sarif.Run, entitledForIacScan bool) error { - if entitledForIacScan { - iacRows := prepareIacs(iacs, true) - log.Output() - return coreutils.PrintTable(formats.ConvertToIacOrSastTableRow(iacRows), "Infrastructure as Code Vulnerabilities", - "✨ No Infrastructure as Code vulnerabilities were found ✨", false) - } - return nil -} - -func PrepareSast(sasts []*sarif.Run) []formats.SourceCodeRow { - return prepareSast(sasts, false) -} - -func prepareSast(sasts []*sarif.Run, isTable bool) []formats.SourceCodeRow { - var sastRows []formats.SourceCodeRow - for _, sastRun := range sasts { - for _, sastResult := range sastRun.Results { - scannerDescription := "" - if rule, err := sastRun.GetRuleById(*sastResult.RuleID); err == nil { - scannerDescription = sarifutils.GetRuleFullDescriptionText(rule) - } - currSeverity, err := severityutils.ParseSeverity(sarifutils.GetResultLevel(sastResult), true) - if err != nil { - log.Warn(fmt.Sprintf("Failed to parse severity `%s` for sast result: %s", sarifutils.GetResultLevel(sastResult), *sastResult.RuleID)) - currSeverity = severityutils.Unknown - } - for _, location := range sastResult.Locations { - codeFlows := sarifutils.GetLocationRelatedCodeFlowsFromResult(location, sastResult) - sastRows = append(sastRows, - formats.SourceCodeRow{ - SeverityDetails: severityutils.GetAsDetails(currSeverity, jasutils.Applicable, isTable), - ScannerDescription: scannerDescription, - Finding: sarifutils.GetResultMsgText(sastResult), - Location: formats.Location{ - File: sarifutils.GetRelativeLocationFileName(location, sastRun.Invocations), - StartLine: sarifutils.GetLocationStartLine(location), - StartColumn: sarifutils.GetLocationStartColumn(location), - EndLine: sarifutils.GetLocationEndLine(location), - EndColumn: sarifutils.GetLocationEndColumn(location), - Snippet: sarifutils.GetLocationSnippet(location), - }, - CodeFlow: codeFlowToLocationFlow(codeFlows, sastRun.Invocations, isTable), - }, - ) - } - } - } - - sort.Slice(sastRows, func(i, j int) bool { - return sastRows[i].SeverityNumValue > sastRows[j].SeverityNumValue - }) - - return sastRows -} - -func codeFlowToLocationFlow(flows []*sarif.CodeFlow, invocations []*sarif.Invocation, isTable bool) (flowRows [][]formats.Location) { - if isTable { - // Not displaying in table - return - } - for _, codeFlow := range flows { - for _, stackTrace := range codeFlow.ThreadFlows { - rowFlow := []formats.Location{} - for _, stackTraceEntry := range stackTrace.Locations { - rowFlow = append(rowFlow, formats.Location{ - File: sarifutils.GetRelativeLocationFileName(stackTraceEntry.Location, invocations), - StartLine: sarifutils.GetLocationStartLine(stackTraceEntry.Location), - StartColumn: sarifutils.GetLocationStartColumn(stackTraceEntry.Location), - EndLine: sarifutils.GetLocationEndLine(stackTraceEntry.Location), - EndColumn: sarifutils.GetLocationEndColumn(stackTraceEntry.Location), - Snippet: sarifutils.GetLocationSnippet(stackTraceEntry.Location), - }) - } - flowRows = append(flowRows, rowFlow) - } - } - return -} - -func PrintSastTable(sast []*sarif.Run, entitledForSastScan bool) error { - if entitledForSastScan { - sastRows := prepareSast(sast, true) - log.Output() - return coreutils.PrintTable(formats.ConvertToIacOrSastTableRow(sastRows), "Static Application Security Testing (SAST)", - "✨ No Static Application Security Testing vulnerabilities were found ✨", false) - } - return nil -} - -func convertJfrogResearchInformation(extendedInfo *services.ExtendedInformation) *formats.JfrogResearchInformation { - if extendedInfo == nil { - return nil - } - var severityReasons []formats.JfrogResearchSeverityReason - for _, severityReason := range extendedInfo.JfrogResearchSeverityReasons { - severityReasons = append(severityReasons, formats.JfrogResearchSeverityReason{ - Name: severityReason.Name, - Description: severityReason.Description, - IsPositive: severityReason.IsPositive, - }) - } - return &formats.JfrogResearchInformation{ - Summary: extendedInfo.ShortDescription, - Details: extendedInfo.FullDescription, - SeverityDetails: formats.SeverityDetails{Severity: extendedInfo.JfrogResearchSeverity}, - SeverityReasons: severityReasons, - Remediation: extendedInfo.Remediation, - } -} - -func splitComponents(impactedPackages map[string]services.Component) (impactedPackagesNames, impactedPackagesVersions, impactedPackagesTypes []string, fixedVersions [][]string, directComponents [][]formats.ComponentRow, impactPaths [][][]formats.ComponentRow, err error) { - if len(impactedPackages) == 0 { - err = errorutils.CheckErrorf("failed while parsing the response from Xray: violation doesn't have any components") - return - } - for currCompId, currComp := range impactedPackages { - currCompName, currCompVersion, currCompType := SplitComponentId(currCompId) - impactedPackagesNames = append(impactedPackagesNames, currCompName) - impactedPackagesVersions = append(impactedPackagesVersions, currCompVersion) - impactedPackagesTypes = append(impactedPackagesTypes, currCompType) - fixedVersions = append(fixedVersions, currComp.FixedVersions) - currDirectComponents, currImpactPaths := getDirectComponentsAndImpactPaths(currComp.ImpactPaths) - directComponents = append(directComponents, currDirectComponents) - impactPaths = append(impactPaths, currImpactPaths) - } - return -} - -var packageTypes = map[string]string{ - "gav": "Maven", - "docker": "Docker", - "rpm": "RPM", - "deb": "Debian", - "nuget": "NuGet", - "generic": "Generic", - "npm": "npm", - "pip": "Python", - "pypi": "Python", - "composer": "Composer", - "go": "Go", - "alpine": "Alpine", -} - -// SplitComponentId splits a Xray component ID to the component name, version and package type. -// In case componentId doesn't contain a version, the returned version will be an empty string. -// In case componentId's format is invalid, it will be returned as the component name -// and empty strings will be returned instead of the version and the package type. -// Examples: -// 1. componentId: "gav://antparent:ant:1.6.5" -// Returned values: -// Component name: "antparent:ant" -// Component version: "1.6.5" -// Package type: "Maven" -// 2. componentId: "generic://sha256:244fd47e07d1004f0aed9c156aa09083c82bf8944eceb67c946ff7430510a77b/foo.jar" -// Returned values: -// Component name: "foo.jar" -// Component version: "" -// Package type: "Generic" -// 3. componentId: "invalid-comp-id" -// Returned values: -// Component name: "invalid-comp-id" -// Component version: "" -// Package type: "" -func SplitComponentId(componentId string) (string, string, string) { - compIdParts := strings.Split(componentId, "://") - // Invalid component ID - if len(compIdParts) != 2 { - return componentId, "", "" - } - - packageType := compIdParts[0] - packageId := compIdParts[1] - - // Generic identifier structure: generic://sha256:/name - if packageType == "generic" { - lastSlashIndex := strings.LastIndex(packageId, "/") - return packageId[lastSlashIndex+1:], "", packageTypes[packageType] - } - - var compName, compVersion string - switch packageType { - case "rpm": - // RPM identifier structure: rpm://os-version:package:epoch-version:version - // os-version is optional. - splitCompId := strings.Split(packageId, ":") - if len(splitCompId) >= 3 { - compName = splitCompId[len(splitCompId)-3] - compVersion = fmt.Sprintf("%s:%s", splitCompId[len(splitCompId)-2], splitCompId[len(splitCompId)-1]) - } - default: - // All other identifiers look like this: package-type://package-name:version. - // Sometimes there's a namespace or a group before the package name, separated by a '/' or a ':'. - lastColonIndex := strings.LastIndex(packageId, ":") - - if lastColonIndex != -1 { - compName = packageId[:lastColonIndex] - compVersion = packageId[lastColonIndex+1:] - } - } - - // If there's an error while parsing the component ID - if compName == "" { - compName = packageId - } - - return compName, compVersion, packageTypes[packageType] -} - -// Gets a slice of the direct dependencies or packages of the scanned component, that depends on the vulnerable package, and converts the impact paths. -func getDirectComponentsAndImpactPaths(impactPaths [][]services.ImpactPathNode) (components []formats.ComponentRow, impactPathsRows [][]formats.ComponentRow) { - componentsMap := make(map[string]formats.ComponentRow) - - // The first node in the impact path is the scanned component itself. The second one is the direct dependency. - impactPathLevel := 1 - for _, impactPath := range impactPaths { - impactPathIndex := impactPathLevel - if len(impactPath) <= impactPathLevel { - impactPathIndex = len(impactPath) - 1 - } - componentId := impactPath[impactPathIndex].ComponentId - if _, exist := componentsMap[componentId]; !exist { - compName, compVersion, _ := SplitComponentId(componentId) - componentsMap[componentId] = formats.ComponentRow{Name: compName, Version: compVersion} - } - - // Convert the impact path - var compImpactPathRows []formats.ComponentRow - for _, pathNode := range impactPath { - nodeCompName, nodeCompVersion, _ := SplitComponentId(pathNode.ComponentId) - compImpactPathRows = append(compImpactPathRows, formats.ComponentRow{ - Name: nodeCompName, - Version: nodeCompVersion, - }) - } - impactPathsRows = append(impactPathsRows, compImpactPathRows) - } - - for _, row := range componentsMap { - components = append(components, row) - } - return -} - -type operationalRiskViolationReadableData struct { - isEol string - cadence string - commits string - committers string - eolMessage string - riskReason string - latestVersion string - newerVersions string -} - -func getOperationalRiskViolationReadableData(violation services.Violation) *operationalRiskViolationReadableData { - isEol, cadence, commits, committers, newerVersions, latestVersion := "N/A", "N/A", "N/A", "N/A", "N/A", "N/A" - if violation.IsEol != nil { - isEol = strconv.FormatBool(*violation.IsEol) - } - if violation.Cadence != nil { - cadence = strconv.FormatFloat(*violation.Cadence, 'f', -1, 64) - } - if violation.Committers != nil { - committers = strconv.FormatInt(int64(*violation.Committers), 10) - } - if violation.Commits != nil { - commits = strconv.FormatInt(*violation.Commits, 10) - } - if violation.NewerVersions != nil { - newerVersions = strconv.FormatInt(int64(*violation.NewerVersions), 10) - } - if violation.LatestVersion != "" { - latestVersion = violation.LatestVersion - } - return &operationalRiskViolationReadableData{ - isEol: isEol, - cadence: cadence, - commits: commits, - committers: committers, - eolMessage: violation.EolMessage, - riskReason: violation.RiskReason, - latestVersion: latestVersion, - newerVersions: newerVersions, - } -} - -// simplifyVulnerabilities returns a new slice of services.Vulnerability that contains only the unique vulnerabilities from the input slice -// The uniqueness of the vulnerabilities is determined by the GetUniqueKey function -func simplifyVulnerabilities(scanVulnerabilities []services.Vulnerability, multipleRoots bool) []services.Vulnerability { - var uniqueVulnerabilities = make(map[string]*services.Vulnerability) - for _, vulnerability := range scanVulnerabilities { - for vulnerableComponentId := range vulnerability.Components { - vulnerableDependency, vulnerableVersion, _ := SplitComponentId(vulnerableComponentId) - packageKey := GetUniqueKey(vulnerableDependency, vulnerableVersion, vulnerability.IssueId, len(vulnerability.Components[vulnerableComponentId].FixedVersions) > 0) - if uniqueVulnerability, exist := uniqueVulnerabilities[packageKey]; exist { - fixedVersions := appendUniqueFixVersions(uniqueVulnerability.Components[vulnerableComponentId].FixedVersions, vulnerability.Components[vulnerableComponentId].FixedVersions...) - impactPaths := appendUniqueImpactPaths(uniqueVulnerability.Components[vulnerableComponentId].ImpactPaths, vulnerability.Components[vulnerableComponentId].ImpactPaths, multipleRoots) - uniqueVulnerabilities[packageKey].Components[vulnerableComponentId] = services.Component{ - FixedVersions: fixedVersions, - ImpactPaths: impactPaths, - } - continue - } - uniqueVulnerabilities[packageKey] = &services.Vulnerability{ - Cves: vulnerability.Cves, - Severity: vulnerability.Severity, - Components: map[string]services.Component{vulnerableComponentId: vulnerability.Components[vulnerableComponentId]}, - IssueId: vulnerability.IssueId, - Technology: vulnerability.Technology, - ExtendedInformation: vulnerability.ExtendedInformation, - Summary: vulnerability.Summary, - } - } - } - // convert map to slice - result := make([]services.Vulnerability, 0, len(uniqueVulnerabilities)) - for _, v := range uniqueVulnerabilities { - result = append(result, *v) - } - return result -} - -// simplifyViolations returns a new slice of services.Violations that contains only the unique violations from the input slice -// The uniqueness of the violations is determined by the GetUniqueKey function -func simplifyViolations(scanViolations []services.Violation, multipleRoots bool) []services.Violation { - var uniqueViolations = make(map[string]*services.Violation) - for _, violation := range scanViolations { - for vulnerableComponentId := range violation.Components { - vulnerableDependency, vulnerableVersion, _ := SplitComponentId(vulnerableComponentId) - packageKey := GetUniqueKey(vulnerableDependency, vulnerableVersion, violation.IssueId, len(violation.Components[vulnerableComponentId].FixedVersions) > 0) - if uniqueVulnerability, exist := uniqueViolations[packageKey]; exist { - fixedVersions := appendUniqueFixVersions(uniqueVulnerability.Components[vulnerableComponentId].FixedVersions, violation.Components[vulnerableComponentId].FixedVersions...) - impactPaths := appendUniqueImpactPaths(uniqueVulnerability.Components[vulnerableComponentId].ImpactPaths, violation.Components[vulnerableComponentId].ImpactPaths, multipleRoots) - uniqueViolations[packageKey].Components[vulnerableComponentId] = services.Component{ - FixedVersions: fixedVersions, - ImpactPaths: impactPaths, - } - continue - } - uniqueViolations[packageKey] = &services.Violation{ - Summary: violation.Summary, - Severity: violation.Severity, - ViolationType: violation.ViolationType, - Components: map[string]services.Component{vulnerableComponentId: violation.Components[vulnerableComponentId]}, - WatchName: violation.WatchName, - IssueId: violation.IssueId, - Cves: violation.Cves, - LicenseKey: violation.LicenseKey, - LicenseName: violation.LicenseName, - RiskReason: violation.RiskReason, - IsEol: violation.IsEol, - EolMessage: violation.EolMessage, - LatestVersion: violation.LatestVersion, - NewerVersions: violation.NewerVersions, - Cadence: violation.Cadence, - Commits: violation.Commits, - Committers: violation.Committers, - ExtendedInformation: violation.ExtendedInformation, - Technology: violation.Technology, - } - } - } - // convert map to slice - result := make([]services.Violation, 0, len(uniqueViolations)) - for _, v := range uniqueViolations { - result = append(result, *v) - } - return result -} - -// appendImpactPathsWithoutDuplicates appends the elements of a source [][]ImpactPathNode struct to a target [][]ImpactPathNode, without adding any duplicate elements. -// This implementation uses the ComponentId field of the ImpactPathNode struct to check for duplicates, as it is guaranteed to be unique. -func appendUniqueImpactPaths(target [][]services.ImpactPathNode, source [][]services.ImpactPathNode, multipleRoots bool) [][]services.ImpactPathNode { - if multipleRoots { - return appendUniqueImpactPathsForMultipleRoots(target, source) - } - impactPathMap := make(map[string][]services.ImpactPathNode) - for _, path := range target { - // The first node component id is the key and the value is the whole path - key := getImpactPathKey(path) - impactPathMap[key] = path - } - - for _, path := range source { - key := getImpactPathKey(path) - if _, exists := impactPathMap[key]; !exists { - impactPathMap[key] = path - target = append(target, path) - } - } - return target -} - -// getImpactPathKey return a key that is used as a key to identify and deduplicate impact paths. -// If an impact path length is equal to directDependencyPathLength, then the direct dependency is the key, and it's in the directDependencyIndex place. -func getImpactPathKey(path []services.ImpactPathNode) string { - key := path[rootIndex].ComponentId - if len(path) == directDependencyPathLength { - key = path[directDependencyIndex].ComponentId - } - return key -} - -// appendUniqueImpactPathsForMultipleRoots appends the source impact path to the target impact path while avoiding duplicates. -// Specifically, it is designed for handling multiple root projects, such as Maven or Gradle, by comparing each pair of paths and identifying the path that is closest to the direct dependency. -func appendUniqueImpactPathsForMultipleRoots(target [][]services.ImpactPathNode, source [][]services.ImpactPathNode) [][]services.ImpactPathNode { - for targetPathIndex, targetPath := range target { - for sourcePathIndex, sourcePath := range source { - var subset []services.ImpactPathNode - if len(sourcePath) <= len(targetPath) { - subset = isImpactPathIsSubset(targetPath, sourcePath) - if len(subset) != 0 { - target[targetPathIndex] = subset - } - } else { - subset = isImpactPathIsSubset(sourcePath, targetPath) - if len(subset) != 0 { - source[sourcePathIndex] = subset - } - } - } - } - - return appendUniqueImpactPaths(target, source, false) -} - -// isImpactPathIsSubset checks if targetPath is a subset of sourcePath, and returns the subset if exists -func isImpactPathIsSubset(target []services.ImpactPathNode, source []services.ImpactPathNode) []services.ImpactPathNode { - var subsetImpactPath []services.ImpactPathNode - impactPathNodesMap := make(map[string]bool) - for _, node := range target { - impactPathNodesMap[node.ComponentId] = true - } - - for _, node := range source { - if impactPathNodesMap[node.ComponentId] { - subsetImpactPath = append(subsetImpactPath, node) - } - } - - if len(subsetImpactPath) == len(target) || len(subsetImpactPath) == len(source) { - return subsetImpactPath - } - return []services.ImpactPathNode{} -} - -// appendUniqueFixVersions returns a new slice of strings that contains elements from both input slices without duplicates -func appendUniqueFixVersions(targetFixVersions []string, sourceFixVersions ...string) []string { - fixVersionsSet := datastructures.MakeSet[string]() - var result []string - for _, fixVersion := range sourceFixVersions { - fixVersionsSet.Add(fixVersion) - result = append(result, fixVersion) - } - - for _, fixVersion := range targetFixVersions { - if exist := fixVersionsSet.Exists(fixVersion); !exist { - result = append(result, fixVersion) - } - } - return result -} - -// GetUniqueKey returns a unique string key of format "vulnerableDependency:vulnerableVersion:xrayID:fixVersionExist" -func GetUniqueKey(vulnerableDependency, vulnerableVersion, xrayID string, fixVersionExist bool) string { - return strings.Join([]string{vulnerableDependency, vulnerableVersion, xrayID, strconv.FormatBool(fixVersionExist)}, ":") -} - -func convertCves(cves []services.Cve) []formats.CveRow { - var cveRows []formats.CveRow - for _, cveObj := range cves { - cveRows = append(cveRows, formats.CveRow{Id: cveObj.Id, CvssV2: cveObj.CvssV2Score, CvssV3: cveObj.CvssV3Score}) - } - return cveRows -} - -func getApplicableCveStatus(entitledForJas bool, applicabilityScanResults []*sarif.Run, cves []formats.CveRow) jasutils.ApplicabilityStatus { - if !entitledForJas || len(applicabilityScanResults) == 0 { - return jasutils.NotScanned - } - if len(cves) == 0 { - return jasutils.NotCovered - } - var applicableStatuses []jasutils.ApplicabilityStatus - for _, cve := range cves { - if cve.Applicability != nil { - applicableStatuses = append(applicableStatuses, jasutils.ApplicabilityStatus(cve.Applicability.Status)) - } - } - return getFinalApplicabilityStatus(applicableStatuses) -} - -func getCveApplicabilityField(cveId string, applicabilityScanResults []*sarif.Run, components map[string]services.Component) *formats.Applicability { - if len(applicabilityScanResults) == 0 { - return nil - } - - applicability := formats.Applicability{} - resultFound := false - var applicabilityStatuses []jasutils.ApplicabilityStatus - for _, applicabilityRun := range applicabilityScanResults { - if rule, _ := applicabilityRun.GetRuleById(jasutils.CveToApplicabilityRuleId(cveId)); rule != nil { - applicability.ScannerDescription = sarifutils.GetRuleFullDescriptionText(rule) - status := getApplicabilityStatusFromRule(rule) - if status != "" { - applicabilityStatuses = append(applicabilityStatuses, status) - } - } - result, _ := applicabilityRun.GetResultByRuleId(jasutils.CveToApplicabilityRuleId(cveId)) - if result == nil { - continue - } - resultFound = true - // Add new evidences from locations - for _, location := range result.Locations { - fileName := sarifutils.GetRelativeLocationFileName(location, applicabilityRun.Invocations) - if shouldDisqualifyEvidence(components, fileName) { - continue - } - applicability.Evidence = append(applicability.Evidence, formats.Evidence{ - Location: formats.Location{ - File: fileName, - StartLine: sarifutils.GetLocationStartLine(location), - StartColumn: sarifutils.GetLocationStartColumn(location), - EndLine: sarifutils.GetLocationEndLine(location), - EndColumn: sarifutils.GetLocationEndColumn(location), - Snippet: sarifutils.GetLocationSnippet(location), - }, - Reason: sarifutils.GetResultMsgText(result), - }) - } - } - switch { - case len(applicabilityStatuses) > 0: - applicability.Status = getFinalApplicabilityStatus(applicabilityStatuses).String() - case !resultFound: - applicability.Status = jasutils.ApplicabilityUndetermined.String() - case len(applicability.Evidence) == 0: - applicability.Status = jasutils.NotApplicable.String() - default: - applicability.Status = jasutils.Applicable.String() - } - return &applicability -} - -func printApplicabilityCveValue(applicabilityStatus jasutils.ApplicabilityStatus, isTable bool) string { - if isTable && (log.IsStdOutTerminal() && log.IsColorsSupported() || os.Getenv("GITLAB_CI") != "") { - if applicabilityStatus == jasutils.Applicable { - return color.New(color.Red).Render(applicabilityStatus) - } else if applicabilityStatus == jasutils.NotApplicable { - return color.New(color.Green).Render(applicabilityStatus) - } - } - return applicabilityStatus.String() -} - -// Relevant only when "third-party-contextual-analysis" flag is on, -// which mean we scan the environment folders as well (node_modules for example...) -// When a certain package is reported applicable, and the evidence found -// is inside the source code of the same package, we should disqualify it. -// -// For example, -// Cve applicability was found inside the 'mquery' package. -// filePath = myProject/node_modules/mquery/badCode.js , disqualify = True. -// Disqualify the above evidence, as the reported applicability is used inside its own package. -// -// filePath = myProject/node_modules/mpath/badCode.js , disqualify = False. -// Found use of a badCode inside the node_modules from a different package, report applicable. -func shouldDisqualifyEvidence(components map[string]services.Component, evidenceFilePath string) (disqualify bool) { - for key := range components { - if !strings.HasPrefix(key, NpmPackageTypeIdentifier) { - return - } - dependencyName := extractDependencyNameFromComponent(key, NpmPackageTypeIdentifier) - // Check both Unix & Windows paths. - if strings.Contains(evidenceFilePath, nodeModules+"/"+dependencyName) || strings.Contains(evidenceFilePath, filepath.Join(nodeModules, dependencyName)) { - return true - } - } - return -} - -func extractDependencyNameFromComponent(key string, techIdentifier string) (dependencyName string) { - packageAndVersion := strings.TrimPrefix(key, techIdentifier) - split := strings.Split(packageAndVersion, ":") - if len(split) < 2 { - return - } - dependencyName = split[0] - return -} - -func getApplicabilityStatusFromRule(rule *sarif.ReportingDescriptor) jasutils.ApplicabilityStatus { - if rule.Properties["applicability"] != nil { - status, ok := rule.Properties["applicability"].(string) - if !ok { - log.Debug(fmt.Sprintf("Failed to get applicability status from rule properties for rule_id %s", rule.ID)) - } - switch status { - case "not_covered": - return jasutils.NotCovered - case "undetermined": - return jasutils.ApplicabilityUndetermined - case "not_applicable": - return jasutils.NotApplicable - case "applicable": - return jasutils.Applicable - } - } - return "" -} - -// If we don't get any statues it means the applicability scanner didn't run -> final value is not scanned -// If at least one cve is applicable -> final value is applicable -// Else if at least one cve is undetermined -> final value is undetermined -// Else if all cves are not covered -> final value is not covered -// Else (case when all cves aren't applicable) -> final value is not applicable -func getFinalApplicabilityStatus(applicabilityStatuses []jasutils.ApplicabilityStatus) jasutils.ApplicabilityStatus { - if len(applicabilityStatuses) == 0 { - return jasutils.NotScanned - } - foundUndetermined := false - foundNotCovered := false - for _, status := range applicabilityStatuses { - if status == jasutils.Applicable { - return jasutils.Applicable - } - if status == jasutils.ApplicabilityUndetermined { - foundUndetermined = true - } - if status == jasutils.NotCovered { - foundNotCovered = true - } - } - if foundUndetermined { - return jasutils.ApplicabilityUndetermined - } - if foundNotCovered { - return jasutils.NotCovered - } - return jasutils.NotApplicable -} diff --git a/utils/resultstable_test.go b/utils/resultstable_test.go deleted file mode 100644 index d0e25ba2..00000000 --- a/utils/resultstable_test.go +++ /dev/null @@ -1,1306 +0,0 @@ -package utils - -import ( - "fmt" - "sort" - "testing" - - "github.com/jfrog/jfrog-cli-security/formats" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" - "github.com/jfrog/jfrog-cli-security/utils/jasutils" - "github.com/owenrumney/go-sarif/v2/sarif" - - "github.com/jfrog/jfrog-client-go/xray/services" - "github.com/stretchr/testify/assert" -) - -// The test only checks cases of returning an error in case of a violation with FailBuild == true -func TestPrintViolationsTable(t *testing.T) { - components := map[string]services.Component{"gav://antparent:ant:1.6.5": {}} - tests := []struct { - violations []services.Violation - expectedError bool - }{ - {[]services.Violation{{Components: components, FailBuild: false}, {Components: components, FailBuild: false}, {Components: components, FailBuild: false}}, false}, - {[]services.Violation{{Components: components, FailBuild: false}, {Components: components, FailBuild: true}, {Components: components, FailBuild: false}}, true}, - {[]services.Violation{{Components: components, FailBuild: true}, {Components: components, FailBuild: true}, {Components: components, FailBuild: true}}, true}, - } - - for _, test := range tests { - err := PrintViolationsTable(test.violations, NewAuditResults(Binary), false, true) - assert.NoError(t, err) - if CheckIfFailBuild([]services.ScanResponse{{Violations: test.violations}}) { - err = NewFailBuildError() - } - assert.Equal(t, test.expectedError, err != nil) - } -} - -func TestSplitComponentId(t *testing.T) { - tests := []struct { - componentId string - expectedCompName string - expectedCompVersion string - expectedCompType string - }{ - {"gav://antparent:ant:1.6.5", "antparent:ant", "1.6.5", "Maven"}, - {"docker://jfrog/artifactory-oss:latest", "jfrog/artifactory-oss", "latest", "Docker"}, - {"rpm://7:rpm-python:7:4.11.3-43.el7", "rpm-python", "7:4.11.3-43.el7", "RPM"}, - {"rpm://rpm-python:7:4.11.3-43.el7", "rpm-python", "7:4.11.3-43.el7", "RPM"}, - {"deb://ubuntu:trustee:acl:2.2.49-2", "ubuntu:trustee:acl", "2.2.49-2", "Debian"}, - {"nuget://log4net:9.0.1", "log4net", "9.0.1", "NuGet"}, - {"generic://sha256:244fd47e07d1004f0aed9c156aa09083c82bf8944eceb67c946ff7430510a77b/foo.jar", "foo.jar", "", "Generic"}, - {"npm://mocha:2.4.5", "mocha", "2.4.5", "npm"}, - {"pip://raven:5.13.0", "raven", "5.13.0", "Python"}, - {"composer://nunomaduro/collision:1.1", "nunomaduro/collision", "1.1", "Composer"}, - {"go://github.com/ethereum/go-ethereum:1.8.2", "github.com/ethereum/go-ethereum", "1.8.2", "Go"}, - {"alpine://3.7:htop:2.0.2-r0", "3.7:htop", "2.0.2-r0", "Alpine"}, - {"invalid-component-id:1.0.0", "invalid-component-id:1.0.0", "", ""}, - } - - for _, test := range tests { - actualCompName, actualCompVersion, actualCompType := SplitComponentId(test.componentId) - assert.Equal(t, test.expectedCompName, actualCompName) - assert.Equal(t, test.expectedCompVersion, actualCompVersion) - assert.Equal(t, test.expectedCompType, actualCompType) - } -} - -func TestGetDirectComponents(t *testing.T) { - tests := []struct { - impactPaths [][]services.ImpactPathNode - expectedComponentRows []formats.ComponentRow - expectedConvImpactPaths [][]formats.ComponentRow - }{ - {[][]services.ImpactPathNode{{services.ImpactPathNode{ComponentId: "gav://jfrog:pack:1.2.3"}}}, []formats.ComponentRow{{Name: "jfrog:pack", Version: "1.2.3"}}, [][]formats.ComponentRow{{{Name: "jfrog:pack", Version: "1.2.3"}}}}, - {[][]services.ImpactPathNode{{services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack2:1.2.3"}}}, []formats.ComponentRow{{Name: "jfrog:pack2", Version: "1.2.3"}}, [][]formats.ComponentRow{{{Name: "jfrog:pack1", Version: "1.2.3"}, {Name: "jfrog:pack2", Version: "1.2.3"}}}}, - {[][]services.ImpactPathNode{{services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack21:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack3:1.2.3"}}, {services.ImpactPathNode{ComponentId: "gav://jfrog:pack1:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack22:1.2.3"}, services.ImpactPathNode{ComponentId: "gav://jfrog:pack3:1.2.3"}}}, []formats.ComponentRow{{Name: "jfrog:pack21", Version: "1.2.3"}, {Name: "jfrog:pack22", Version: "1.2.3"}}, [][]formats.ComponentRow{{{Name: "jfrog:pack1", Version: "1.2.3"}, {Name: "jfrog:pack21", Version: "1.2.3"}, {Name: "jfrog:pack3", Version: "1.2.3"}}, {{Name: "jfrog:pack1", Version: "1.2.3"}, {Name: "jfrog:pack22", Version: "1.2.3"}, {Name: "jfrog:pack3", Version: "1.2.3"}}}}, - } - - for _, test := range tests { - actualComponentRows, actualConvImpactPaths := getDirectComponentsAndImpactPaths(test.impactPaths) - assert.ElementsMatch(t, test.expectedComponentRows, actualComponentRows) - assert.ElementsMatch(t, test.expectedConvImpactPaths, actualConvImpactPaths) - } -} - -func TestSimplifyVulnerability(t *testing.T) { - vulnerabilities := []services.Vulnerability{ - {Components: map[string]services.Component{"gav://jfrogpack:1.0.0": {ImpactPaths: [][]services.ImpactPathNode{ - {{ComponentId: "build://dort:1"}, - {ComponentId: "generic://sha256:1bcd6597181d476796e206e176ccc185b4709ff28fb069c42e7f7f67c6a0ff28/multi3-3.7-20240806.082023-11.war", - FullPath: "multi3-3.7-20240806.082023-11.war"}, - {ComponentId: "gav://jfrogpack:1.0.0", FullPath: "jfrogpack:-1.0.0.jar"}}, - }}}}, - {Components: map[string]services.Component{"gav://jfrogpack:1.0.1": {}}}, - {Components: map[string]services.Component{"gav://jfrogpack:1.0.0": {ImpactPaths: [][]services.ImpactPathNode{ - {{ComponentId: "build://dort:1"}, - {ComponentId: "gav://jfrogpack:1.0.0", FullPath: "jfrogpack:-1.0.0.jar"}}, - }}}}, - {Components: map[string]services.Component{"gav://jfrogpack:1.0.2": {}}}, - } - tests := []struct { - testName string - expectedImpactPathRoots [][]services.ImpactPathNode - isMultipleRoots bool - }{ - { - "Test multiple roots false", - [][]services.ImpactPathNode{ - {{ComponentId: "build://dort:1"}, - {ComponentId: "generic://sha256:1bcd6597181d476796e206e176ccc185b4709ff28fb069c42e7f7f67c6a0ff28/multi3-3.7-20240806.082023-11.war", - FullPath: "multi3-3.7-20240806.082023-11.war"}, - {ComponentId: "gav://jfrogpack:1.0.0", FullPath: "jfrogpack:-1.0.0.jar"}}, - {{ComponentId: "build://dort:1"}, - {ComponentId: "gav://jfrogpack:1.0.0", FullPath: "jfrogpack:-1.0.0.jar"}}, - }, - false, - }, - { - "Test multiple roots true", - [][]services.ImpactPathNode{ - {{ComponentId: "build://dort:1"}, - {ComponentId: "gav://jfrogpack:1.0.0", FullPath: "jfrogpack:-1.0.0.jar"}}, - }, - true, - }, - } - - for _, test := range tests { - t.Run(test.testName, func(t *testing.T) { - testSimplifyVulnerabilityRoot(t, vulnerabilities, test.isMultipleRoots, test.expectedImpactPathRoots) - }) - } - -} - -func testSimplifyVulnerabilityRoot(t *testing.T, vulnerabilities []services.Vulnerability, multipleRoots bool, expectedImpactPath [][]services.ImpactPathNode) { - simplifiedVulnerabilities := simplifyVulnerabilities(vulnerabilities, multipleRoots) - assert.Equal(t, len(vulnerabilities)-1, len(simplifiedVulnerabilities)) - for _, vulnerability := range simplifiedVulnerabilities { - for key := range vulnerability.Components { - if key == "gav://jfrogpack:1.0.0" { - assert.Equal(t, expectedImpactPath, vulnerability.Components[key].ImpactPaths) - } - } - } -} - -func TestSimplifyViolation(t *testing.T) { - violations := []services.Violation{ - {Components: map[string]services.Component{"gav://jfrogpack:1.0.0": {ImpactPaths: [][]services.ImpactPathNode{ - {{ComponentId: "build://dort:1"}, - {ComponentId: "generic://sha256:1bcd6597181d476796e206e176ccc185b4709ff28fb069c42e7f7f67c6a0ff28/multi3-3.7-20240806.082023-11.war", - FullPath: "multi3-3.7-20240806.082023-11.war"}, - {ComponentId: "gav://jfrogpack:1.0.0", FullPath: "jfrogpack:-1.0.0.jar"}}, - }}}, FailBuild: true}, - {Components: map[string]services.Component{"gav://jfrogpack:1.0.1": {}}, FailBuild: true}, - {Components: map[string]services.Component{"gav://jfrogpack:1.0.0": {ImpactPaths: [][]services.ImpactPathNode{ - {{ComponentId: "build://dort:1"}, - {ComponentId: "gav://jfrogpack:1.0.0", FullPath: "jfrogpack:-1.0.0.jar"}}, - }}}, FailBuild: true}, - {Components: map[string]services.Component{"gav://jfrogpack:1.0.2": {}}, FailBuild: true}, - } - tests := []struct { - testName string - expectedImpactPathRoots [][]services.ImpactPathNode - isMultipleRoots bool - }{ - { - "Test multiple roots false", - [][]services.ImpactPathNode{ - {{ComponentId: "build://dort:1"}, - {ComponentId: "generic://sha256:1bcd6597181d476796e206e176ccc185b4709ff28fb069c42e7f7f67c6a0ff28/multi3-3.7-20240806.082023-11.war", - FullPath: "multi3-3.7-20240806.082023-11.war"}, - {ComponentId: "gav://jfrogpack:1.0.0", FullPath: "jfrogpack:-1.0.0.jar"}}, - {{ComponentId: "build://dort:1"}, - {ComponentId: "gav://jfrogpack:1.0.0", FullPath: "jfrogpack:-1.0.0.jar"}}, - }, - false, - }, - { - "Test multiple roots true", - [][]services.ImpactPathNode{ - {{ComponentId: "build://dort:1"}, - {ComponentId: "gav://jfrogpack:1.0.0", FullPath: "jfrogpack:-1.0.0.jar"}}, - }, - true, - }, - } - - for _, test := range tests { - t.Run(test.testName, func(t *testing.T) { - testSimplifyViolationRoot(t, violations, test.isMultipleRoots, test.expectedImpactPathRoots) - }) - } -} - -func testSimplifyViolationRoot(t *testing.T, violations []services.Violation, multipleRoots bool, expectedImpactPath [][]services.ImpactPathNode) { - simplifiedViolations := simplifyViolations(violations, multipleRoots) - assert.Equal(t, len(violations)-1, len(simplifiedViolations)) - for _, violation := range simplifiedViolations { - for key := range violation.Components { - if key == "gav://jfrogpack:1.0.0" { - assert.Equal(t, expectedImpactPath, violation.Components[key].ImpactPaths) - } - } - } -} - -func TestGetOperationalRiskReadableData(t *testing.T) { - tests := []struct { - testName string - violation services.Violation - expectedResults *operationalRiskViolationReadableData - }{ - { - "Empty Operational Risk Violation", - services.Violation{IsEol: nil, LatestVersion: "", NewerVersions: nil, - Cadence: nil, Commits: nil, Committers: nil, RiskReason: "", EolMessage: ""}, - &operationalRiskViolationReadableData{"N/A", "N/A", "N/A", "N/A", "", "", "N/A", "N/A"}, - }, - { - "Detailed Operational Risk Violation with all fields", - services.Violation{IsEol: newBoolPtr(true), LatestVersion: "1.2.3", NewerVersions: newIntPtr(5), - Cadence: newFloat64Ptr(3.5), Commits: newInt64Ptr(55), Committers: newIntPtr(10), EolMessage: "no maintainers", RiskReason: "EOL"}, - &operationalRiskViolationReadableData{"true", "3.5", "55", "10", "no maintainers", "EOL", "1.2.3", "5"}, - }, - } - - for _, test := range tests { - t.Run(test.testName, func(t *testing.T) { - results := getOperationalRiskViolationReadableData(test.violation) - assert.Equal(t, test.expectedResults, results) - }) - } -} - -// Test Simplified Violations as this is the data we eventually parse in the tables -func TestGetOperationalRiskSimplifiedViolations(t *testing.T) { - violations := []services.Violation{ - {Components: map[string]services.Component{"gav://antparent:ant:1.6.4": {}}, IsEol: nil, LatestVersion: "", NewerVersions: nil, - Cadence: nil, Commits: nil, Committers: nil, RiskReason: "", EolMessage: ""}, - {Components: map[string]services.Component{"gav://antparent:ant:1.6.5": {}}, IsEol: newBoolPtr(true), LatestVersion: "1.2.3", NewerVersions: newIntPtr(5), - Cadence: newFloat64Ptr(3.5), Commits: newInt64Ptr(55), Committers: newIntPtr(10), EolMessage: "no maintainers", RiskReason: "EOL"}, - } - simplifiedViolations := simplifyViolations(violations, true) - - // Sorting the violations based on component key so that the order will be unified for the expected results - // gav://antparent:ant:1.6.4 -> gav://antparent:ant:1.6.5 (if other tests are added, add it in order) - // In the code the violations returned from the function are being sorted at the end of the logic for printing - sortViolationsSliceBasedOnComponentVersion(simplifiedViolations) - tests := []struct { - testName string - violation services.Violation - expectedResults *operationalRiskViolationReadableData - }{ - { - "Empty Operational Risk Violation", - simplifiedViolations[0], - &operationalRiskViolationReadableData{"N/A", "N/A", "N/A", "N/A", "", "", "N/A", "N/A"}, - }, - { - "Detailed Operational Risk Violation with all fields", - simplifiedViolations[1], - &operationalRiskViolationReadableData{"true", "3.5", "55", "10", "no maintainers", "EOL", "1.2.3", "5"}, - }, - } - - for _, test := range tests { - t.Run(test.testName, func(t *testing.T) { - results := getOperationalRiskViolationReadableData(test.violation) - assert.Equal(t, test.expectedResults, results) - }) - } -} - -func getFirstKey(components map[string]services.Component) string { - for key := range components { - return key - } - return "" -} -func sortViolationsSliceBasedOnComponentVersion(simplifiedViolations []services.Violation) { - sort.Slice(simplifiedViolations, func(i, j int) bool { - return getFirstKey(simplifiedViolations[i].Components) < getFirstKey(simplifiedViolations[j].Components) - }) -} - -func TestIsImpactPathIsSubset(t *testing.T) { - testCases := []struct { - name string - target, source, expectedResult []services.ImpactPathNode - }{ - {"subset found in both target and source", - []services.ImpactPathNode{{ComponentId: "B"}, {ComponentId: "C"}}, - []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "C"}}, - []services.ImpactPathNode{{ComponentId: "B"}, {ComponentId: "C"}}, - }, - {"subset not found in both target and source", - []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "D"}}, - []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "C"}}, - []services.ImpactPathNode{}, - }, - {"target and source are identical", - []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}}, - []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}}, - []services.ImpactPathNode{{ComponentId: "A"}, {ComponentId: "B"}}, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - result := isImpactPathIsSubset(tc.target, tc.source) - assert.Equal(t, tc.expectedResult, result) - }) - } -} - -func TestAppendUniqueFixVersions(t *testing.T) { - testCases := []struct { - targetFixVersions []string - sourceFixVersions []string - expectedResult []string - }{ - { - targetFixVersions: []string{"1.0", "1.1"}, - sourceFixVersions: []string{"2.0", "2.1"}, - expectedResult: []string{"1.0", "1.1", "2.0", "2.1"}, - }, - { - targetFixVersions: []string{"1.0", "1.1"}, - sourceFixVersions: []string{"1.1", "2.0"}, - expectedResult: []string{"1.0", "1.1", "2.0"}, - }, - { - targetFixVersions: []string{}, - sourceFixVersions: []string{"1.0", "1.1"}, - expectedResult: []string{"1.0", "1.1"}, - }, - { - targetFixVersions: []string{"1.0", "1.1"}, - sourceFixVersions: []string{}, - expectedResult: []string{"1.0", "1.1"}, - }, - } - - for _, tc := range testCases { - t.Run(fmt.Sprintf("target:%v, source:%v", tc.targetFixVersions, tc.sourceFixVersions), func(t *testing.T) { - result := appendUniqueFixVersions(tc.targetFixVersions, tc.sourceFixVersions...) - assert.ElementsMatch(t, tc.expectedResult, result) - }) - } -} - -func TestGetUniqueKey(t *testing.T) { - vulnerableDependency := "test-dependency" - vulnerableVersion := "1.0" - expectedKey := "test-dependency:1.0:XRAY-12234:true" - key := GetUniqueKey(vulnerableDependency, vulnerableVersion, "XRAY-12234", true) - assert.Equal(t, expectedKey, key) - - expectedKey = "test-dependency:1.0:XRAY-12143:false" - key = GetUniqueKey(vulnerableDependency, vulnerableVersion, "XRAY-12143", false) - assert.Equal(t, expectedKey, key) -} - -func TestAppendUniqueImpactPathsForMultipleRoots(t *testing.T) { - testCases := []struct { - name string - target [][]services.ImpactPathNode - source [][]services.ImpactPathNode - expectedResult [][]services.ImpactPathNode - }{ - { - name: "subset is found in both target and source", - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "C"}}, - {{ComponentId: "D"}, {ComponentId: "E"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "B"}, {ComponentId: "C"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - expectedResult: [][]services.ImpactPathNode{ - {{ComponentId: "B"}, {ComponentId: "C"}}, - {{ComponentId: "D"}, {ComponentId: "E"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - }, - { - name: "subset is not found in both target and source", - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "C"}}, - {{ComponentId: "D"}, {ComponentId: "E"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "B"}, {ComponentId: "C"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - expectedResult: [][]services.ImpactPathNode{ - {{ComponentId: "B"}, {ComponentId: "C"}}, - {{ComponentId: "D"}, {ComponentId: "E"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - }, - { - name: "target slice is empty", - target: [][]services.ImpactPathNode{}, - source: [][]services.ImpactPathNode{ - {{ComponentId: "E"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - expectedResult: [][]services.ImpactPathNode{ - {{ComponentId: "E"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - }, - { - name: "source slice is empty", - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - source: [][]services.ImpactPathNode{}, - expectedResult: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - }, - { - name: "target and source slices are identical", - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - expectedResult: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - }, - { - name: "target and source slices contain multiple subsets", - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}, {ComponentId: "E"}}, - {{ComponentId: "C"}, {ComponentId: "D"}, {ComponentId: "F"}}, - {{ComponentId: "G"}, {ComponentId: "H"}}, - }, - expectedResult: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - {{ComponentId: "G"}, {ComponentId: "H"}}, - }, - }, - } - - for _, test := range testCases { - t.Run(test.name, func(t *testing.T) { - assert.Equal(t, test.expectedResult, appendUniqueImpactPathsForMultipleRoots(test.target, test.source)) - }) - } -} - -func TestGetImpactPathKey(t *testing.T) { - testCases := []struct { - path []services.ImpactPathNode - expectedKey string - }{ - { - path: []services.ImpactPathNode{ - {ComponentId: "A"}, - {ComponentId: "B"}, - }, - expectedKey: "B", - }, - { - path: []services.ImpactPathNode{ - {ComponentId: "A"}, - }, - expectedKey: "A", - }, - } - - for _, test := range testCases { - key := getImpactPathKey(test.path) - assert.Equal(t, test.expectedKey, key) - } -} - -func TestAppendUniqueImpactPaths(t *testing.T) { - testCases := []struct { - name string - multipleRoots bool - target [][]services.ImpactPathNode - source [][]services.ImpactPathNode - expected [][]services.ImpactPathNode - }{ - { - name: "Test case 1: Unique impact paths found", - multipleRoots: false, - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}}, - {{ComponentId: "B"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "C"}}, - {{ComponentId: "D"}}, - }, - expected: [][]services.ImpactPathNode{ - {{ComponentId: "A"}}, - {{ComponentId: "B"}}, - {{ComponentId: "C"}}, - {{ComponentId: "D"}}, - }, - }, - { - name: "Test case 2: No unique impact paths found", - multipleRoots: false, - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}}, - {{ComponentId: "B"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "A"}}, - {{ComponentId: "B"}}, - }, - expected: [][]services.ImpactPathNode{ - {{ComponentId: "A"}}, - {{ComponentId: "B"}}, - }, - }, - { - name: "Test case 3: paths in source are not in target", - multipleRoots: false, - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "E"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - expected: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - {{ComponentId: "E"}}, - {{ComponentId: "F"}, {ComponentId: "G"}}, - }, - }, - { - name: "Test case 4: paths in source are already in target", - multipleRoots: false, - target: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - source: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - expected: [][]services.ImpactPathNode{ - {{ComponentId: "A"}, {ComponentId: "B"}}, - {{ComponentId: "C"}, {ComponentId: "D"}}, - }, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - result := appendUniqueImpactPaths(tc.target, tc.source, tc.multipleRoots) - assert.Equal(t, tc.expected, result) - }) - } -} - -func TestGetApplicableCveValue(t *testing.T) { - testCases := []struct { - name string - scanResults *ExtendedScanResults - cves []services.Cve - expectedResult jasutils.ApplicabilityStatus - expectedCves []formats.CveRow - }{ - { - name: "not entitled for jas", - scanResults: &ExtendedScanResults{EntitledForJas: false}, - expectedResult: jasutils.NotScanned, - }, - { - name: "no cves", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateResultWithOneLocation("fileName1", 0, 1, 0, 0, "snippet1", "applic_testCve1", "info"), - sarifutils.CreateDummyPassingResult("applic_testCve2"), - ), - }, - EntitledForJas: true, - }, - cves: nil, - expectedResult: jasutils.NotCovered, - expectedCves: nil, - }, - { - name: "applicable cve", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateDummyPassingResult("applic_testCve1"), - sarifutils.CreateResultWithOneLocation("fileName2", 1, 0, 0, 0, "snippet2", "applic_testCve2", "warning"), - ), - }, - EntitledForJas: true, - }, - cves: []services.Cve{{Id: "testCve2"}}, - expectedResult: jasutils.Applicable, - expectedCves: []formats.CveRow{{Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.Applicable.String()}}}, - }, - { - name: "undetermined cve", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateDummyPassingResult("applic_testCve1"), - sarifutils.CreateResultWithOneLocation("fileName3", 0, 1, 0, 0, "snippet3", "applic_testCve2", "info"), - ), - }, - EntitledForJas: true, - }, - cves: []services.Cve{{Id: "testCve3"}}, - expectedResult: jasutils.ApplicabilityUndetermined, - expectedCves: []formats.CveRow{{Id: "testCve3"}}, - }, - { - name: "not applicable cve", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateDummyPassingResult("applic_testCve1"), - sarifutils.CreateDummyPassingResult("applic_testCve2"), - ), - }, - EntitledForJas: true, - }, - cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - expectedResult: jasutils.NotApplicable, - expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}, {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}}, - }, - { - name: "applicable and not applicable cves", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateDummyPassingResult("applic_testCve1"), - sarifutils.CreateResultWithOneLocation("fileName4", 1, 0, 0, 0, "snippet", "applic_testCve2", "warning"), - ), - }, - EntitledForJas: true, - }, - cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - expectedResult: jasutils.Applicable, - expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}, {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.Applicable.String()}}}, - }, - { - name: "undetermined and not applicable cves", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyPassingResult("applic_testCve1")), - }, - EntitledForJas: true}, - cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - expectedResult: jasutils.ApplicabilityUndetermined, - expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}, {Id: "testCve2"}}, - }, - { - name: "new scan statuses - applicable wins all statuses", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", sarifutils.CreateDummyPassingResult("applic_testCve1")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_testCve2")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve3")), - }, - EntitledForJas: true}, - cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}, {Id: "testCve3"}}, - expectedResult: jasutils.Applicable, - expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.Applicable.String()}}, - {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}, - {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.NotCovered.String()}}, - }, - }, - { - name: "new scan statuses - not covered wins not applicable", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve1")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_testCve2")), - }, - EntitledForJas: true}, - cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - expectedResult: jasutils.NotCovered, - expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.NotCovered.String()}}, - {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}, - }, - }, - { - name: "new scan statuses - undetermined wins not covered", - scanResults: &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve1")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "undetermined", sarifutils.CreateDummyPassingResult("applic_testCve2")), - }, - EntitledForJas: true}, - cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, - expectedResult: jasutils.ApplicabilityUndetermined, - expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.NotCovered.String()}}, - {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.ApplicabilityUndetermined.String()}}, - }, - }, - } - - for _, testCase := range testCases { - cves := convertCves(testCase.cves) - for i := range cves { - cves[i].Applicability = getCveApplicabilityField(cves[i].Id, testCase.scanResults.ApplicabilityScanResults, nil) - } - applicableValue := getApplicableCveStatus(testCase.scanResults.EntitledForJas, testCase.scanResults.ApplicabilityScanResults, cves) - assert.Equal(t, testCase.expectedResult, applicableValue) - if assert.True(t, len(testCase.expectedCves) == len(cves)) { - for i := range cves { - if testCase.expectedCves[i].Applicability != nil && assert.NotNil(t, cves[i].Applicability) { - assert.Equal(t, testCase.expectedCves[i].Applicability.Status, cves[i].Applicability.Status) - } - } - } - } -} - -func TestSortVulnerabilityOrViolationRows(t *testing.T) { - testCases := []struct { - name string - rows []formats.VulnerabilityOrViolationRow - expectedOrder []string - }{ - { - name: "Sort by severity with different severity values", - rows: []formats.VulnerabilityOrViolationRow{ - { - Summary: "Summary 1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "High", - SeverityNumValue: 9, - }, - ImpactedDependencyName: "Dependency 1", - ImpactedDependencyVersion: "1.0.0", - }, - FixedVersions: []string{}, - }, - { - Summary: "Summary 2", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "Critical", - SeverityNumValue: 12, - }, - ImpactedDependencyName: "Dependency 2", - ImpactedDependencyVersion: "2.0.0", - }, - FixedVersions: []string{"1.0.0"}, - }, - { - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "Medium", - SeverityNumValue: 6, - }, - ImpactedDependencyName: "Dependency 3", - ImpactedDependencyVersion: "3.0.0", - }, - Summary: "Summary 3", - FixedVersions: []string{}, - }, - }, - expectedOrder: []string{"Dependency 2", "Dependency 1", "Dependency 3"}, - }, - { - name: "Sort by severity with same severity values, but different fixed versions", - rows: []formats.VulnerabilityOrViolationRow{ - { - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "Critical", - SeverityNumValue: 12, - }, - ImpactedDependencyName: "Dependency 1", - ImpactedDependencyVersion: "1.0.0", - }, - Summary: "Summary 1", - FixedVersions: []string{"1.0.0"}, - }, - { - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "Critical", - SeverityNumValue: 12, - }, - ImpactedDependencyName: "Dependency 2", - ImpactedDependencyVersion: "2.0.0", - }, - Summary: "Summary 2", - FixedVersions: []string{}, - }, - }, - expectedOrder: []string{"Dependency 1", "Dependency 2"}, - }, - { - name: "Sort by severity with same severity values different applicability", - rows: []formats.VulnerabilityOrViolationRow{ - { - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "Critical", - SeverityNumValue: 13, - }, - ImpactedDependencyName: "Dependency 1", - ImpactedDependencyVersion: "1.0.0", - }, - Summary: "Summary 1", - Applicable: jasutils.Applicable.String(), - FixedVersions: []string{"1.0.0"}, - }, - { - Summary: "Summary 2", - Applicable: jasutils.NotApplicable.String(), - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "Critical", - SeverityNumValue: 11, - }, - ImpactedDependencyName: "Dependency 2", - ImpactedDependencyVersion: "2.0.0", - }, - }, - { - Summary: "Summary 3", - Applicable: jasutils.ApplicabilityUndetermined.String(), - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{ - Severity: "Critical", - SeverityNumValue: 12, - }, - ImpactedDependencyName: "Dependency 3", - ImpactedDependencyVersion: "2.0.0", - }, - }, - }, - expectedOrder: []string{"Dependency 1", "Dependency 3", "Dependency 2"}, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - sortVulnerabilityOrViolationRows(tc.rows) - - for i, row := range tc.rows { - assert.Equal(t, tc.expectedOrder[i], row.ImpactedDependencyName) - } - }) - } -} - -func TestShouldDisqualifyEvidence(t *testing.T) { - testCases := []struct { - name string - component map[string]services.Component - filePath string - disqualify bool - }{ - { - name: "package folders", - component: map[string]services.Component{"npm://protobufjs:6.11.2": {}}, - filePath: "file:///Users/jfrog/test/node_modules/protobufjs/src/badCode.js", - disqualify: true, - }, { - name: "nested folders", - component: map[string]services.Component{"npm://protobufjs:6.11.2": {}}, - filePath: "file:///Users/jfrog/test/node_modules/someDep/node_modules/protobufjs/src/badCode.js", - disqualify: true, - }, { - name: "applicability in node modules", - component: map[string]services.Component{"npm://protobufjs:6.11.2": {}}, - filePath: "file:///Users/jfrog/test/node_modules/mquery/src/badCode.js", - disqualify: false, - }, { - // Only npm supported - name: "not npm", - component: map[string]services.Component{"yarn://protobufjs:6.11.2": {}}, - filePath: "file:///Users/jfrog/test/node_modules/protobufjs/src/badCode.js", - disqualify: false, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, tc.disqualify, shouldDisqualifyEvidence(tc.component, tc.filePath)) - }) - } -} - -func TestPrepareIac(t *testing.T) { - testCases := []struct { - name string - input []*sarif.Run - expectedOutput []formats.SourceCodeRow - }{ - { - name: "No Iac run", - input: []*sarif.Run{}, - expectedOutput: []formats.SourceCodeRow{}, - }, - { - name: "Prepare Iac run - no results", - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults(), - }, - expectedOutput: []formats.SourceCodeRow{}, - }, - { - name: "Prepare Iac run - with results", - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateResultWithLocations("iac finding", "rule1", "info", - sarifutils.CreateLocation("file://wd/file", 1, 2, 3, 4, "snippet"), - sarifutils.CreateLocation("file://wd/file2", 5, 6, 7, 8, "other-snippet"), - ), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("wd")), - }), - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateResultWithLocations("other iac finding", "rule2", "error", - sarifutils.CreateLocation("file://wd2/file3", 1, 2, 3, 4, "snippet"), - ), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("wd2")), - }), - }, - expectedOutput: []formats.SourceCodeRow{ - { - SeverityDetails: formats.SeverityDetails{ - Severity: "High", - SeverityNumValue: 17, - }, - Finding: "other iac finding", - Location: formats.Location{ - File: "file3", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "snippet", - }, - }, - { - SeverityDetails: formats.SeverityDetails{ - Severity: "Medium", - SeverityNumValue: 14, - }, - Finding: "iac finding", - Location: formats.Location{ - File: "file", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "snippet", - }, - }, - { - SeverityDetails: formats.SeverityDetails{ - Severity: "Medium", - SeverityNumValue: 14, - }, - Finding: "iac finding", - Location: formats.Location{ - File: "file2", - StartLine: 5, - StartColumn: 6, - EndLine: 7, - EndColumn: 8, - Snippet: "other-snippet", - }, - }, - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.ElementsMatch(t, tc.expectedOutput, prepareIacs(tc.input, false)) - }) - } -} - -func TestPrepareSecrets(t *testing.T) { - testCases := []struct { - name string - input []*sarif.Run - expectedOutput []formats.SourceCodeRow - }{ - { - name: "No Secret run", - input: []*sarif.Run{}, - expectedOutput: []formats.SourceCodeRow{}, - }, - { - name: "Prepare Secret run - no results", - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults(), - }, - expectedOutput: []formats.SourceCodeRow{}, - }, - { - name: "Prepare Secret run - with results", - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateResultWithLocations("secret finding", "rule1", "info", - sarifutils.CreateLocation("file://wd/file", 1, 2, 3, 4, "some-secret-snippet"), - sarifutils.CreateLocation("file://wd/file2", 5, 6, 7, 8, "other-secret-snippet"), - ), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("wd")), - }), - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateResultWithLocations("other secret finding", "rule2", "note", - sarifutils.CreateLocation("file://wd2/file3", 1, 2, 3, 4, "some-secret-snippet"), - ), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("wd2")), - }), - }, - expectedOutput: []formats.SourceCodeRow{ - { - SeverityDetails: formats.SeverityDetails{ - Severity: "Low", - SeverityNumValue: 11, - }, - Finding: "other secret finding", - Location: formats.Location{ - File: "file3", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "some-secret-snippet", - }, - }, - { - SeverityDetails: formats.SeverityDetails{ - Severity: "Medium", - SeverityNumValue: 14, - }, - Finding: "secret finding", - Location: formats.Location{ - File: "file", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "some-secret-snippet", - }, - }, - { - SeverityDetails: formats.SeverityDetails{ - Severity: "Medium", - SeverityNumValue: 14, - }, - Finding: "secret finding", - Location: formats.Location{ - File: "file2", - StartLine: 5, - StartColumn: 6, - EndLine: 7, - EndColumn: 8, - Snippet: "other-secret-snippet", - }, - }, - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.ElementsMatch(t, tc.expectedOutput, prepareSecrets(tc.input, false)) - }) - } -} - -func TestPrepareSast(t *testing.T) { - testCases := []struct { - name string - input []*sarif.Run - expectedOutput []formats.SourceCodeRow - }{ - { - name: "No Sast run", - input: []*sarif.Run{}, - expectedOutput: []formats.SourceCodeRow{}, - }, - { - name: "Prepare Sast run - no results", - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults(), - }, - expectedOutput: []formats.SourceCodeRow{}, - }, - { - name: "Prepare Sast run - with results", - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(), - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateResultWithLocations("sast finding", "rule1", "info", - sarifutils.CreateLocation("file://wd/file", 1, 2, 3, 4, "snippet"), - sarifutils.CreateLocation("file://wd/file2", 5, 6, 7, 8, "other-snippet"), - ).WithCodeFlows([]*sarif.CodeFlow{ - sarifutils.CreateCodeFlow(sarifutils.CreateThreadFlow( - sarifutils.CreateLocation("file://wd/file2", 0, 2, 0, 2, "snippetA"), - sarifutils.CreateLocation("file://wd/file", 1, 2, 3, 4, "snippet"), - )), - sarifutils.CreateCodeFlow(sarifutils.CreateThreadFlow( - sarifutils.CreateLocation("file://wd/file4", 1, 0, 1, 8, "snippetB"), - sarifutils.CreateLocation("file://wd/file", 1, 2, 3, 4, "snippet"), - )), - }), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("wd")), - }), - sarifutils.CreateRunWithDummyResults( - sarifutils.CreateResultWithLocations("other sast finding", "rule2", "error", - sarifutils.CreateLocation("file://wd2/file3", 1, 2, 3, 4, "snippet"), - ), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("wd2")), - }), - }, - expectedOutput: []formats.SourceCodeRow{ - { - SeverityDetails: formats.SeverityDetails{ - Severity: "High", - SeverityNumValue: 17, - }, - Finding: "other sast finding", - Location: formats.Location{ - File: "file3", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "snippet", - }, - }, - { - SeverityDetails: formats.SeverityDetails{ - Severity: "Medium", - SeverityNumValue: 14, - }, - Finding: "sast finding", - Location: formats.Location{ - File: "file", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "snippet", - }, - CodeFlow: [][]formats.Location{ - { - { - File: "file2", - StartLine: 0, - StartColumn: 2, - EndLine: 0, - EndColumn: 2, - Snippet: "snippetA", - }, - { - File: "file", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "snippet", - }, - }, - { - { - File: "file4", - StartLine: 1, - StartColumn: 0, - EndLine: 1, - EndColumn: 8, - Snippet: "snippetB", - }, - { - File: "file", - StartLine: 1, - StartColumn: 2, - EndLine: 3, - EndColumn: 4, - Snippet: "snippet", - }, - }, - }, - }, - { - SeverityDetails: formats.SeverityDetails{ - Severity: "Medium", - SeverityNumValue: 14, - }, - Finding: "sast finding", - Location: formats.Location{ - File: "file2", - StartLine: 5, - StartColumn: 6, - EndLine: 7, - EndColumn: 8, - Snippet: "other-snippet", - }, - }, - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.ElementsMatch(t, tc.expectedOutput, prepareSast(tc.input, false)) - }) - } -} - -func TestGetFinalApplicabilityStatus(t *testing.T) { - testCases := []struct { - name string - input []jasutils.ApplicabilityStatus - expectedOutput jasutils.ApplicabilityStatus - }{ - { - name: "applicable wins all statuses", - input: []jasutils.ApplicabilityStatus{jasutils.ApplicabilityUndetermined, jasutils.Applicable, jasutils.NotCovered, jasutils.NotApplicable}, - expectedOutput: jasutils.Applicable, - }, - { - name: "undetermined wins not covered", - input: []jasutils.ApplicabilityStatus{jasutils.NotCovered, jasutils.ApplicabilityUndetermined, jasutils.NotCovered, jasutils.NotApplicable}, - expectedOutput: jasutils.ApplicabilityUndetermined, - }, - { - name: "not covered wins not applicable", - input: []jasutils.ApplicabilityStatus{jasutils.NotApplicable, jasutils.NotCovered, jasutils.NotApplicable}, - expectedOutput: jasutils.NotCovered, - }, - { - name: "all statuses are not applicable", - input: []jasutils.ApplicabilityStatus{jasutils.NotApplicable, jasutils.NotApplicable, jasutils.NotApplicable}, - expectedOutput: jasutils.NotApplicable, - }, - { - name: "no statuses", - input: []jasutils.ApplicabilityStatus{}, - expectedOutput: jasutils.NotScanned, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, tc.expectedOutput, getFinalApplicabilityStatus(tc.input)) - }) - } -} - -func newBoolPtr(v bool) *bool { - return &v -} - -func newIntPtr(v int) *int { - return &v -} - -func newInt64Ptr(v int64) *int64 { - return &v -} - -func newFloat64Ptr(v float64) *float64 { - return &v -} diff --git a/utils/resultwriter.go b/utils/resultwriter.go deleted file mode 100644 index 331d7724..00000000 --- a/utils/resultwriter.go +++ /dev/null @@ -1,1163 +0,0 @@ -package utils - -import ( - "bytes" - "encoding/json" - "fmt" - "os" - "path/filepath" - "regexp" - "strconv" - "strings" - - "github.com/jfrog/gofrog/datastructures" - "github.com/jfrog/jfrog-cli-core/v2/common/format" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-security/formats" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" - "github.com/jfrog/jfrog-cli-security/utils/jasutils" - "github.com/jfrog/jfrog-cli-security/utils/severityutils" - "github.com/jfrog/jfrog-cli-security/utils/techutils" - clientUtils "github.com/jfrog/jfrog-client-go/utils" - "github.com/jfrog/jfrog-client-go/utils/errorutils" - "github.com/jfrog/jfrog-client-go/utils/io/fileutils" - "github.com/jfrog/jfrog-client-go/utils/log" - "github.com/jfrog/jfrog-client-go/xray/services" - "github.com/owenrumney/go-sarif/v2/sarif" - "golang.org/x/exp/slices" -) - -const ( - BaseDocumentationURL = "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/" - CurrentWorkflowNameEnvVar = "GITHUB_WORKFLOW" - CurrentWorkflowRunNumberEnvVar = "GITHUB_RUN_NUMBER" - CurrentWorkflowWorkspaceEnvVar = "GITHUB_WORKSPACE" - - MissingCveScore = "0" - maxPossibleCve = 10.0 - - // #nosec G101 -- Not credentials. - patchedBinarySecretScannerToolName = "JFrog Binary Secrets Scanner" - jfrogFingerprintAlgorithmName = "jfrogFingerprintHash" -) - -var ( - GithubBaseWorkflowDir = filepath.Join(".github", "workflows") - dockerJasLocationPathPattern = regexp.MustCompile(`.*[\\/](?P[^\\/]+)[\\/](?P[0-9a-fA-F]+)[\\/](?P.*)`) - dockerScaComponentNamePattern = regexp.MustCompile(`(?P[^__]+)__(?P[0-9a-fA-F]+)\.tar`) -) - -type ResultsWriter struct { - // The scan results. - results *Results - // SimpleJsonError Errors to be added to output of the SimpleJson format. - simpleJsonError []formats.SimpleJsonError - // Format The output format. - format format.OutputFormat - // IncludeVulnerabilities If true, include all vulnerabilities as part of the output. - includeVulnerabilities bool - // If true, include violations as part of the output. - hasViolationContext bool - // IncludeLicenses If true, also include license violations as part of the output. - includeLicenses bool - // IsMultipleRoots multipleRoots is set to true, in case the given results array contains (or may contain) results of several projects (like in binary scan). - isMultipleRoots bool - // PrintExtended, If true, show extended results. - printExtended bool - // For table format - show table only for the given subScansPreformed - subScansPreformed []SubScanType - // Messages - Option array of messages, to be displayed if the format is Table - messages []string -} - -func NewResultsWriter(scanResults *Results) *ResultsWriter { - return &ResultsWriter{results: scanResults} -} - -func GetScaScanFileName(r *Results) string { - if len(r.ScaResults) > 0 { - return r.ScaResults[0].Target - } - return "" -} - -func (rw *ResultsWriter) SetHasViolationContext(hasViolationContext bool) *ResultsWriter { - rw.hasViolationContext = hasViolationContext - return rw -} - -func (rw *ResultsWriter) SetOutputFormat(f format.OutputFormat) *ResultsWriter { - rw.format = f - return rw -} - -func (rw *ResultsWriter) SetSimpleJsonError(jsonErrors []formats.SimpleJsonError) *ResultsWriter { - rw.simpleJsonError = jsonErrors - return rw -} - -func (rw *ResultsWriter) SetIncludeVulnerabilities(includeVulnerabilities bool) *ResultsWriter { - rw.includeVulnerabilities = includeVulnerabilities - return rw -} - -func (rw *ResultsWriter) SetIncludeLicenses(licenses bool) *ResultsWriter { - rw.includeLicenses = licenses - return rw -} - -func (rw *ResultsWriter) SetIsMultipleRootProject(isMultipleRootProject bool) *ResultsWriter { - rw.isMultipleRoots = isMultipleRootProject - return rw -} - -func (rw *ResultsWriter) SetPrintExtendedTable(extendedTable bool) *ResultsWriter { - rw.printExtended = extendedTable - return rw -} - -func (rw *ResultsWriter) SetExtraMessages(messages []string) *ResultsWriter { - rw.messages = messages - return rw -} - -func (rw *ResultsWriter) SetSubScansPreformed(subScansPreformed []SubScanType) *ResultsWriter { - rw.subScansPreformed = subScansPreformed - return rw -} - -// PrintScanResults prints the scan results in the specified format. -// Note that errors are printed only with SimpleJson format. -func (rw *ResultsWriter) PrintScanResults() error { - switch rw.format { - case format.Table: - return rw.printScanResultsTables() - case format.SimpleJson: - jsonTable, err := rw.convertScanToSimpleJson() - if err != nil { - return err - } - return PrintJson(jsonTable) - case format.Json: - return PrintJson(rw.results.GetScaScansXrayResults()) - case format.Sarif: - return PrintSarif(rw.results, rw.isMultipleRoots, rw.includeLicenses) - } - return nil -} - -func (rw *ResultsWriter) printScanResultsTables() (err error) { - printMessages(rw.messages) - violations, vulnerabilities, licenses := SplitScanResults(rw.results.ScaResults) - if rw.results.IsIssuesFound() { - var resultsPath string - if resultsPath, err = writeJsonResults(rw.results); err != nil { - return - } - printMessage(coreutils.PrintTitle("The full scan results are available here: ") + coreutils.PrintLink(resultsPath)) - } - log.Output() - if shouldPrintTable(rw.subScansPreformed, ScaScan, rw.results.ResultType) { - if rw.hasViolationContext { - if err = PrintViolationsTable(violations, rw.results, rw.isMultipleRoots, rw.printExtended); err != nil { - return - } - } - if rw.includeVulnerabilities { - if err = PrintVulnerabilitiesTable(vulnerabilities, rw.results, rw.isMultipleRoots, rw.printExtended, rw.results.ResultType); err != nil { - return - } - } - if rw.includeLicenses { - if err = PrintLicensesTable(licenses, rw.printExtended, rw.results.ResultType); err != nil { - return - } - } - } - if shouldPrintTable(rw.subScansPreformed, SecretsScan, rw.results.ResultType) { - if err = PrintSecretsTable(rw.results.ExtendedScanResults.SecretsScanResults, rw.results.ExtendedScanResults.EntitledForJas); err != nil { - return - } - } - if shouldPrintTable(rw.subScansPreformed, IacScan, rw.results.ResultType) { - if err = PrintIacTable(rw.results.ExtendedScanResults.IacScanResults, rw.results.ExtendedScanResults.EntitledForJas); err != nil { - return - } - } - if !shouldPrintTable(rw.subScansPreformed, SastScan, rw.results.ResultType) { - return nil - } - return PrintSastTable(rw.results.ExtendedScanResults.SastScanResults, rw.results.ExtendedScanResults.EntitledForJas) -} - -func shouldPrintTable(requestedScans []SubScanType, subScan SubScanType, scanType CommandType) bool { - if scanType.IsTargetBinary() && (subScan == IacScan || subScan == SastScan) { - return false - } - return len(requestedScans) == 0 || slices.Contains(requestedScans, subScan) -} - -func printMessages(messages []string) { - if len(messages) > 0 { - log.Output() - } - for _, m := range messages { - printMessage(m) - } -} - -func printMessage(message string) { - log.Output("💬" + message) -} - -func GenerateSarifReportFromResults(results *Results, isMultipleRoots, includeLicenses bool, allowedLicenses []string) (report *sarif.Report, err error) { - report, err = sarifutils.NewReport() - if err != nil { - return - } - xrayRun, err := convertXrayResponsesToSarifRun(results, isMultipleRoots, includeLicenses, allowedLicenses) - if err != nil { - return - } - - report.Runs = append(report.Runs, patchRunsToPassIngestionRules(ScaScan, results, xrayRun)...) - report.Runs = append(report.Runs, patchRunsToPassIngestionRules(IacScan, results, results.ExtendedScanResults.IacScanResults...)...) - report.Runs = append(report.Runs, patchRunsToPassIngestionRules(SecretsScan, results, results.ExtendedScanResults.SecretsScanResults...)...) - report.Runs = append(report.Runs, patchRunsToPassIngestionRules(SastScan, results, results.ExtendedScanResults.SastScanResults...)...) - - return -} - -func convertXrayResponsesToSarifRun(results *Results, isMultipleRoots, includeLicenses bool, allowedLicenses []string) (run *sarif.Run, err error) { - xrayJson, err := ConvertXrayScanToSimpleJson(results, isMultipleRoots, includeLicenses, true, allowedLicenses) - if err != nil { - return - } - xrayRun := sarif.NewRunWithInformationURI("JFrog Xray Scanner", BaseDocumentationURL+"sca") - xrayRun.Tool.Driver.Version = &results.XrayVersion - if len(xrayJson.Vulnerabilities) > 0 || len(xrayJson.SecurityViolations) > 0 || len(xrayJson.LicensesViolations) > 0 { - if err = extractXrayIssuesToSarifRun(results, xrayRun, xrayJson); err != nil { - return - } - } - run = xrayRun - return -} - -func extractXrayIssuesToSarifRun(results *Results, run *sarif.Run, xrayJson formats.SimpleJsonResults) error { - for _, vulnerability := range xrayJson.Vulnerabilities { - if err := addXrayCveIssueToSarifRun(results, vulnerability, run); err != nil { - return err - } - } - for _, violation := range xrayJson.SecurityViolations { - if err := addXrayCveIssueToSarifRun(results, violation, run); err != nil { - return err - } - } - for _, license := range xrayJson.LicensesViolations { - if err := addXrayLicenseViolationToSarifRun(results, license, run); err != nil { - return err - } - } - return nil -} - -func addXrayCveIssueToSarifRun(results *Results, issue formats.VulnerabilityOrViolationRow, run *sarif.Run) (err error) { - maxCveScore, err := findMaxCVEScore(issue.Cves) - if err != nil { - return - } - location, err := getXrayIssueLocationIfValidExists(issue.Technology, run) - if err != nil { - return - } - formattedDirectDependencies, err := getDirectDependenciesFormatted(issue.Components) - if err != nil { - return - } - cveId := GetIssueIdentifier(issue.Cves, issue.IssueId) - markdownDescription := getSarifTableDescription(formattedDirectDependencies, maxCveScore, issue.Applicable, issue.FixedVersions) - addXrayIssueToSarifRun( - results.ResultType, - cveId, - issue.ImpactedDependencyName, - issue.ImpactedDependencyVersion, - severityutils.GetSeverity(issue.Severity), - maxCveScore, - issue.Summary, - getXrayIssueSarifHeadline(issue.ImpactedDependencyName, issue.ImpactedDependencyVersion, cveId), - markdownDescription, - issue.Components, - location, - run, - ) - return -} - -func addXrayLicenseViolationToSarifRun(results *Results, license formats.LicenseRow, run *sarif.Run) (err error) { - formattedDirectDependencies, err := getDirectDependenciesFormatted(license.Components) - if err != nil { - return - } - addXrayIssueToSarifRun( - results.ResultType, - license.LicenseKey, - license.ImpactedDependencyName, - license.ImpactedDependencyVersion, - severityutils.GetSeverity(license.Severity), - MissingCveScore, - getLicenseViolationSummary(license.ImpactedDependencyName, license.ImpactedDependencyVersion, license.LicenseKey), - getXrayLicenseSarifHeadline(license.ImpactedDependencyName, license.ImpactedDependencyVersion, license.LicenseKey), - getLicenseViolationMarkdown(license.ImpactedDependencyName, license.ImpactedDependencyVersion, license.LicenseKey, formattedDirectDependencies), - license.Components, - getXrayIssueLocation(""), - run, - ) - return -} - -func addXrayIssueToSarifRun(resultType CommandType, issueId, impactedDependencyName, impactedDependencyVersion string, severity severityutils.Severity, severityScore, summary, title, markdownDescription string, components []formats.ComponentRow, location *sarif.Location, run *sarif.Run) { - // Add rule if not exists - ruleId := getXrayIssueSarifRuleId(impactedDependencyName, impactedDependencyVersion, issueId) - if rule, _ := run.GetRuleById(ruleId); rule == nil { - addXrayRule(ruleId, title, severityScore, summary, markdownDescription, run) - } - // Add result for each component - for _, directDependency := range components { - msg := getXrayIssueSarifHeadline(directDependency.Name, directDependency.Version, issueId) - if result := run.CreateResultForRule(ruleId).WithMessage(sarif.NewTextMessage(msg)).WithLevel(severityutils.SeverityToSarifSeverityLevel(severity).String()); location != nil { - if resultType == DockerImage { - algorithm, layer := getLayerContentFromComponentId(directDependency.Name) - if layer != "" { - logicalLocation := sarifutils.NewLogicalLocation(layer, "layer") - if algorithm != "" { - logicalLocation.Properties = map[string]interface{}{"algorithm": algorithm} - } - location.LogicalLocations = append(location.LogicalLocations, logicalLocation) - } - } - result.AddLocation(location) - } - } -} - -func getDescriptorFullPath(tech techutils.Technology, run *sarif.Run) (string, error) { - descriptors := tech.GetPackageDescriptor() - if len(descriptors) == 1 { - // Generate the full path - return sarifutils.GetFullLocationFileName(strings.TrimSpace(descriptors[0]), run.Invocations), nil - } - for _, descriptor := range descriptors { - // If multiple options return first to match - absolutePath := sarifutils.GetFullLocationFileName(strings.TrimSpace(descriptor), run.Invocations) - if exists, err := fileutils.IsFileExists(absolutePath, false); err != nil { - return "", err - } else if exists { - return absolutePath, nil - } - } - return "", nil -} - -// Get the descriptor location with the Xray issues if exists. -func getXrayIssueLocationIfValidExists(tech techutils.Technology, run *sarif.Run) (location *sarif.Location, err error) { - descriptorPath, err := getDescriptorFullPath(tech, run) - if err != nil { - return - } - return getXrayIssueLocation(descriptorPath), nil -} - -func getXrayIssueLocation(filePath string) *sarif.Location { - if strings.TrimSpace(filePath) == "" { - filePath = "Package-Descriptor" - } - return sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://" + filePath))) -} - -func addXrayRule(ruleId, ruleDescription, maxCveScore, summary, markdownDescription string, run *sarif.Run) { - rule := run.AddRule(ruleId) - - if maxCveScore != MissingCveScore { - cveRuleProperties := sarif.NewPropertyBag() - cveRuleProperties.Add(severityutils.SarifSeverityRuleProperty, maxCveScore) - rule.WithProperties(cveRuleProperties.Properties) - } - - rule.WithDescription(ruleDescription) - rule.WithHelp(&sarif.MultiformatMessageString{ - Text: &summary, - Markdown: &markdownDescription, - }) -} - -func ConvertXrayScanToSimpleJson(results *Results, isMultipleRoots, includeLicenses, simplifiedOutput bool, allowedLicenses []string) (formats.SimpleJsonResults, error) { - violations, vulnerabilities, licenses := SplitScanResults(results.ScaResults) - jsonTable := formats.SimpleJsonResults{} - if len(vulnerabilities) > 0 { - vulJsonTable, err := PrepareVulnerabilities(vulnerabilities, results, isMultipleRoots, simplifiedOutput) - if err != nil { - return formats.SimpleJsonResults{}, err - } - jsonTable.Vulnerabilities = vulJsonTable - } - if includeLicenses || len(allowedLicenses) > 0 { - licJsonTable, err := PrepareLicenses(licenses) - if err != nil { - return formats.SimpleJsonResults{}, err - } - if includeLicenses { - jsonTable.Licenses = licJsonTable - } - jsonTable.LicensesViolations = GetViolatedLicenses(allowedLicenses, licJsonTable) - } - if len(violations) > 0 { - secViolationsJsonTable, licViolationsJsonTable, opRiskViolationsJsonTable, err := PrepareViolations(violations, results, isMultipleRoots, simplifiedOutput) - if err != nil { - return formats.SimpleJsonResults{}, err - } - jsonTable.SecurityViolations = secViolationsJsonTable - jsonTable.LicensesViolations = licViolationsJsonTable - jsonTable.OperationalRiskViolations = opRiskViolationsJsonTable - } - jsonTable.MultiScanId = results.MultiScanId - return jsonTable, nil -} - -func GetViolatedLicenses(allowedLicenses []string, licenses []formats.LicenseRow) (violatedLicenses []formats.LicenseRow) { - if len(allowedLicenses) == 0 { - return - } - for _, license := range licenses { - if !slices.Contains(allowedLicenses, license.LicenseKey) { - violatedLicenses = append(violatedLicenses, license) - } - } - return -} - -func (rw *ResultsWriter) convertScanToSimpleJson() (formats.SimpleJsonResults, error) { - jsonTable, err := ConvertXrayScanToSimpleJson(rw.results, rw.isMultipleRoots, rw.includeLicenses, false, nil) - if err != nil { - return formats.SimpleJsonResults{}, err - } - if len(rw.results.ExtendedScanResults.SecretsScanResults) > 0 { - jsonTable.Secrets = PrepareSecrets(rw.results.ExtendedScanResults.SecretsScanResults) - } - if len(rw.results.ExtendedScanResults.IacScanResults) > 0 { - jsonTable.Iacs = PrepareIacs(rw.results.ExtendedScanResults.IacScanResults) - } - if len(rw.results.ExtendedScanResults.SastScanResults) > 0 { - jsonTable.Sast = PrepareSast(rw.results.ExtendedScanResults.SastScanResults) - } - jsonTable.Errors = rw.simpleJsonError - - return jsonTable, nil -} - -func GetIssueIdentifier(cvesRow []formats.CveRow, issueId string) string { - var identifier string - if len(cvesRow) != 0 { - var cvesBuilder strings.Builder - for _, cve := range cvesRow { - cvesBuilder.WriteString(cve.Id + ", ") - } - identifier = strings.TrimSuffix(cvesBuilder.String(), ", ") - } - if identifier == "" { - identifier = issueId - } - - return identifier -} - -func getXrayIssueSarifRuleId(depName, version, key string) string { - return fmt.Sprintf("%s_%s_%s", key, depName, version) -} - -func getXrayIssueSarifHeadline(depName, version, key string) string { - return strings.TrimSpace(fmt.Sprintf("[%s] %s %s", key, depName, version)) -} - -func getXrayLicenseSarifHeadline(depName, version, key string) string { - return fmt.Sprintf("License violation [%s] %s %s", key, depName, version) -} - -func getLicenseViolationSummary(depName, version, key string) string { - return fmt.Sprintf("Dependency %s version %s is using a license (%s) that is not allowed.", depName, version, key) -} - -func getLicenseViolationMarkdown(depName, version, key, formattedDirectDependencies string) string { - return fmt.Sprintf("**The following direct dependencies are utilizing the `%s %s` dependency with `%s` license violation:**\n%s", depName, version, key, formattedDirectDependencies) -} - -func getDirectDependenciesFormatted(directDependencies []formats.ComponentRow) (string, error) { - var formattedDirectDependencies strings.Builder - for _, dependency := range directDependencies { - if _, err := formattedDirectDependencies.WriteString(fmt.Sprintf("`%s %s`
", dependency.Name, dependency.Version)); err != nil { - return "", err - } - } - return strings.TrimSuffix(formattedDirectDependencies.String(), "
"), nil -} - -func getSarifTableDescription(formattedDirectDependencies, maxCveScore, applicable string, fixedVersions []string) string { - descriptionFixVersions := "No fix available" - if len(fixedVersions) > 0 { - descriptionFixVersions = strings.Join(fixedVersions, ", ") - } - if applicable == jasutils.NotScanned.String() { - return fmt.Sprintf("| Severity Score | Direct Dependencies | Fixed Versions |\n| :---: | :----: | :---: |\n| %s | %s | %s |", - maxCveScore, formattedDirectDependencies, descriptionFixVersions) - } - return fmt.Sprintf("| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| %s | %s | %s | %s |", - maxCveScore, applicable, formattedDirectDependencies, descriptionFixVersions) -} - -func findMaxCVEScore(cves []formats.CveRow) (string, error) { - maxCve := 0.0 - for _, cve := range cves { - if cve.CvssV3 == "" { - continue - } - floatCve, err := strconv.ParseFloat(cve.CvssV3, 32) - if err != nil { - return "", err - } - if floatCve > maxCve { - maxCve = floatCve - } - // if found maximum possible cve score, no need to keep iterating - if maxCve == maxPossibleCve { - break - } - } - strCve := fmt.Sprintf("%.1f", maxCve) - - return strCve, nil -} - -func patchRules(subScanType SubScanType, cmdResults *Results, rules ...*sarif.ReportingDescriptor) (patched []*sarif.ReportingDescriptor) { - patched = []*sarif.ReportingDescriptor{} - for _, rule := range rules { - // Github code scanning ingestion rules rejects rules without help content. - // Patch by transferring the full description to the help field. - if rule.Help == nil && rule.FullDescription != nil { - rule.Help = rule.FullDescription - } - // SARIF1001 - if both 'id' and 'name' are present, they must be different. If they are identical, the tool must omit the 'name' property. - if rule.Name != nil && rule.ID == *rule.Name { - rule.Name = nil - } - if cmdResults.ResultType.IsTargetBinary() && subScanType == SecretsScan { - // Patch the rule name in case of binary scan - sarifutils.SetRuleShortDescriptionText(fmt.Sprintf("[Secret in Binary found] %s", sarifutils.GetRuleShortDescriptionText(rule)), rule) - } - patched = append(patched, rule) - } - return -} - -func patchResults(subScanType SubScanType, cmdResults *Results, run *sarif.Run, results ...*sarif.Result) (patched []*sarif.Result) { - patched = []*sarif.Result{} - for _, result := range results { - if len(result.Locations) == 0 { - // Github code scanning ingestion rules rejects results without locations. - // Patch by removing results without locations. - log.Debug(fmt.Sprintf("[%s] Removing result [ruleId=%s] without locations: %s", subScanType.String(), sarifutils.GetResultRuleId(result), sarifutils.GetResultMsgText(result))) - continue - } - if cmdResults.ResultType.IsTargetBinary() { - var markdown string - if subScanType == SecretsScan { - markdown = getSecretInBinaryMarkdownMsg(cmdResults, result) - } else { - markdown = getScaInBinaryMarkdownMsg(cmdResults, result) - } - sarifutils.SetResultMsgMarkdown(markdown, result) - // For Binary scans, override the physical location if applicable (after data already used for markdown) - convertBinaryPhysicalLocations(cmdResults, run, result) - // Calculate the fingerprints if not exists - if !sarifutils.IsFingerprintsExists(result) { - if err := calculateResultFingerprints(cmdResults.ResultType, run, result); err != nil { - log.Warn(fmt.Sprintf("Failed to calculate the fingerprint for result [ruleId=%s]: %s", sarifutils.GetResultRuleId(result), err.Error())) - } - } - } - patched = append(patched, result) - } - return patched -} - -func patchRunsToPassIngestionRules(subScanType SubScanType, cmdResults *Results, runs ...*sarif.Run) []*sarif.Run { - // Since we run in temp directories files should be relative - // Patch by converting the file paths to relative paths according to the invocations - convertPaths(cmdResults.ResultType, subScanType, runs...) - for _, run := range runs { - if cmdResults.ResultType.IsTargetBinary() && subScanType == SecretsScan { - // Patch the tool name in case of binary scan - sarifutils.SetRunToolName(patchedBinarySecretScannerToolName, run) - } - run.Tool.Driver.Rules = patchRules(subScanType, cmdResults, run.Tool.Driver.Rules...) - run.Results = patchResults(subScanType, cmdResults, run, run.Results...) - } - return runs -} - -func convertPaths(commandType CommandType, subScanType SubScanType, runs ...*sarif.Run) { - // Convert base on invocation for source code - sarifutils.ConvertRunsPathsToRelative(runs...) - if !(commandType == DockerImage && subScanType == SecretsScan) { - return - } - for _, run := range runs { - for _, result := range run.Results { - // For Docker secret scan, patch the logical location if not exists - patchDockerSecretLocations(result) - } - } -} - -// Patch the URI to be the file path from sha// -// Extract the layer from the location URI, adds it as a logical location kind "layer" -func patchDockerSecretLocations(result *sarif.Result) { - for _, location := range result.Locations { - algorithm, layerHash, relativePath := getLayerContentFromPath(sarifutils.GetLocationFileName(location)) - if layerHash != "" { - // Set Logical location kind "layer" with the layer hash - logicalLocation := sarifutils.NewLogicalLocation(layerHash, "layer") - if algorithm != "" { - logicalLocation.Properties = sarif.Properties(map[string]interface{}{"algorithm": algorithm}) - } - location.LogicalLocations = append(location.LogicalLocations, logicalLocation) - } - if relativePath != "" { - sarifutils.SetLocationFileName(location, relativePath) - } - } -} - -func convertBinaryPhysicalLocations(cmdResults *Results, run *sarif.Run, result *sarif.Result) { - if patchedLocation := getPatchedBinaryLocation(cmdResults, run); patchedLocation != "" { - for _, location := range result.Locations { - // Patch the location - Reset the uri and region - location.PhysicalLocation = sarifutils.NewPhysicalLocation(patchedLocation) - } - } -} - -func getPatchedBinaryLocation(cmdResults *Results, run *sarif.Run) (patchedLocation string) { - if cmdResults.ResultType == DockerImage { - if patchedLocation = getDockerfileLocationIfExists(run); patchedLocation != "" { - return - } - } - return getWorkflowFileLocationIfExists() -} - -func getDockerfileLocationIfExists(run *sarif.Run) string { - potentialLocations := []string{filepath.Clean("Dockerfile"), sarifutils.GetFullLocationFileName("Dockerfile", run.Invocations)} - for _, location := range potentialLocations { - if exists, err := fileutils.IsFileExists(location, false); err == nil && exists { - return location - } - } - if workspace := os.Getenv(CurrentWorkflowWorkspaceEnvVar); workspace != "" { - if exists, err := fileutils.IsFileExists(filepath.Join(workspace, "Dockerfile"), false); err == nil && exists { - return filepath.Join(workspace, "Dockerfile") - } - } - return "" -} - -func getGithubWorkflowsDirIfExists() string { - if exists, err := fileutils.IsDirExists(GithubBaseWorkflowDir, false); err == nil && exists { - return GithubBaseWorkflowDir - } - if workspace := os.Getenv(CurrentWorkflowWorkspaceEnvVar); workspace != "" { - if exists, err := fileutils.IsDirExists(filepath.Join(workspace, GithubBaseWorkflowDir), false); err == nil && exists { - return filepath.Join(workspace, GithubBaseWorkflowDir) - } - } - return "" -} - -func getWorkflowFileLocationIfExists() (location string) { - workflowName := os.Getenv(CurrentWorkflowNameEnvVar) - if workflowName == "" { - return - } - workflowsDir := getGithubWorkflowsDirIfExists() - if workflowsDir == "" { - return - } - currentWd, err := os.Getwd() - if err != nil { - log.Warn(fmt.Sprintf("Failed to get the current working directory to get workflow file location: %s", err.Error())) - return - } - // Check if exists in the .github/workflows directory as file name or in the content, return the file path or empty string - if files, err := fileutils.ListFiles(workflowsDir, false); err == nil && len(files) > 0 { - for _, file := range files { - if strings.Contains(file, workflowName) { - return strings.TrimPrefix(file, currentWd) - } - } - for _, file := range files { - if content, err := fileutils.ReadFile(file); err == nil && strings.Contains(string(content), workflowName) { - return strings.TrimPrefix(file, currentWd) - } - } - } - return -} - -func getSecretInBinaryMarkdownMsg(cmdResults *Results, result *sarif.Result) string { - if cmdResults.ResultType != Binary && cmdResults.ResultType != DockerImage { - return "" - } - content := "🔒 Found Secrets in Binary" - if cmdResults.ResultType == DockerImage { - content += " docker" - } - content += " scanning:" - return content + getBaseBinaryDescriptionMarkdown(SecretsScan, cmdResults, result) -} - -func getScaInBinaryMarkdownMsg(cmdResults *Results, result *sarif.Result) string { - return sarifutils.GetResultMsgText(result) + getBaseBinaryDescriptionMarkdown(ScaScan, cmdResults, result) -} - -func getBaseBinaryDescriptionMarkdown(subScanType SubScanType, cmdResults *Results, result *sarif.Result) (content string) { - // If in github action, add the workflow name and run number - if workflowLocation := getWorkflowFileLocationIfExists(); workflowLocation != "" { - content += fmt.Sprintf("\nGithub Actions Workflow: %s", workflowLocation) - } - if os.Getenv(CurrentWorkflowRunNumberEnvVar) != "" { - content += fmt.Sprintf("\nRun: %s", os.Getenv(CurrentWorkflowRunNumberEnvVar)) - } - // If is docker image, add the image tag - if cmdResults.ResultType == DockerImage { - if imageTag := getDockerImageTag(cmdResults); imageTag != "" { - content += fmt.Sprintf("\nImage: %s", imageTag) - } - } - var location *sarif.Location - if len(result.Locations) > 0 { - location = result.Locations[0] - } - return content + getBinaryLocationMarkdownString(cmdResults.ResultType, subScanType, location) -} - -func getDockerImageTag(cmdResults *Results) string { - if cmdResults.ResultType != DockerImage || len(cmdResults.ScaResults) == 0 { - return "" - } - for _, scaResults := range cmdResults.ScaResults { - if scaResults.Name != "" { - return scaResults.Name - } - } - return filepath.Base(cmdResults.ScaResults[0].Target) -} - -// If command is docker prepare the markdown string for the location: -// * Layer: -// * Filepath: -// * Evidence: -func getBinaryLocationMarkdownString(commandType CommandType, subScanType SubScanType, location *sarif.Location) (content string) { - if location == nil { - return "" - } - if commandType == DockerImage { - if layer, algorithm := getDockerLayer(location); layer != "" { - if algorithm != "" { - content += fmt.Sprintf("\nLayer (%s): %s", algorithm, layer) - } else { - content += fmt.Sprintf("\nLayer: %s", layer) - } - } - } - if subScanType != SecretsScan { - return - } - if locationFilePath := sarifutils.GetLocationFileName(location); locationFilePath != "" { - content += fmt.Sprintf("\nFilepath: %s", locationFilePath) - } - if snippet := sarifutils.GetLocationSnippet(location); snippet != "" { - content += fmt.Sprintf("\nEvidence: %s", snippet) - } - return -} - -func getDockerLayer(location *sarif.Location) (layer, algorithm string) { - // If location has logical location with kind "layer" return it - if logicalLocation := sarifutils.GetLogicalLocation("layer", location); logicalLocation != nil && logicalLocation.Name != nil { - layer = *logicalLocation.Name - if algorithmValue, ok := logicalLocation.Properties["algorithm"].(string); ok { - algorithm = algorithmValue - } - return - } - return -} - -// Match: -// Extract algorithm, hash and relative path -func getLayerContentFromPath(content string) (algorithm string, layerHash string, relativePath string) { - matches := dockerJasLocationPathPattern.FindStringSubmatch(content) - if len(matches) == 0 { - return - } - algorithm = matches[dockerJasLocationPathPattern.SubexpIndex("algorithm")] - layerHash = matches[dockerJasLocationPathPattern.SubexpIndex("hash")] - relativePath = matches[dockerJasLocationPathPattern.SubexpIndex("relativePath")] - return -} - -// Match: ://:/ -// Extract algorithm and hash -func getLayerContentFromComponentId(componentId string) (algorithm string, layerHash string) { - matches := dockerScaComponentNamePattern.FindStringSubmatch(componentId) - if len(matches) == 0 { - return - } - algorithm = matches[dockerScaComponentNamePattern.SubexpIndex("algorithm")] - layerHash = matches[dockerScaComponentNamePattern.SubexpIndex("hash")] - return -} - -// According to the SARIF specification: -// To determine whether a result from a subsequent run is logically the same as a result from the baseline, -// there must be a way to use information contained in the result to construct a stable identifier for the result. We refer to this identifier as a fingerprint. -// A result management system SHOULD construct a fingerprint by using information contained in the SARIF file such as: -// The name of the tool that produced the result, the rule id, the file system path to the analysis target... -func calculateResultFingerprints(resultType CommandType, run *sarif.Run, result *sarif.Result) error { - if !resultType.IsTargetBinary() { - return nil - } - ids := []string{sarifutils.GetRunToolName(run), sarifutils.GetResultRuleId(result)} - for _, location := range sarifutils.GetResultFileLocations(result) { - ids = append(ids, strings.ReplaceAll(location, string(filepath.Separator), "/")) - } - ids = append(ids, sarifutils.GetResultLocationSnippets(result)...) - // Calculate the hash value and set the fingerprint to the result - hashValue, err := Md5Hash(ids...) - if err != nil { - return err - } - sarifutils.SetResultFingerprint(jfrogFingerprintAlgorithmName, hashValue, result) - return nil -} - -// Splits scan responses into aggregated lists of violations, vulnerabilities and licenses. -func SplitScanResults(results []*ScaScanResult) ([]services.Violation, []services.Vulnerability, []services.License) { - var violations []services.Violation - var vulnerabilities []services.Vulnerability - var licenses []services.License - for _, scan := range results { - for _, result := range scan.XrayResults { - violations = append(violations, result.Violations...) - vulnerabilities = append(vulnerabilities, result.Vulnerabilities...) - licenses = append(licenses, result.Licenses...) - } - } - return violations, vulnerabilities, licenses -} - -func writeJsonResults(results *Results) (resultsPath string, err error) { - out, err := fileutils.CreateTempFile() - if errorutils.CheckError(err) != nil { - return - } - defer func() { - e := out.Close() - if err == nil { - err = e - } - }() - bytesRes, err := JSONMarshalNotEscaped(&results) - if errorutils.CheckError(err) != nil { - return - } - var content bytes.Buffer - err = json.Indent(&content, bytesRes, "", " ") - if errorutils.CheckError(err) != nil { - return - } - _, err = out.Write(content.Bytes()) - if errorutils.CheckError(err) != nil { - return - } - resultsPath = out.Name() - return -} - -func WriteSarifResultsAsString(report *sarif.Report, escape bool) (sarifStr string, err error) { - var out []byte - if escape { - out, err = json.Marshal(report) - } else { - out, err = JSONMarshalNotEscaped(report) - } - if err != nil { - return "", errorutils.CheckError(err) - } - return clientUtils.IndentJson(out), nil -} - -func JSONMarshalNotEscaped(t interface{}) ([]byte, error) { - buffer := &bytes.Buffer{} - encoder := json.NewEncoder(buffer) - encoder.SetEscapeHTML(false) - err := encoder.Encode(t) - return buffer.Bytes(), err -} - -func PrintJson(output interface{}) error { - results, err := JSONMarshalNotEscaped(output) - if err != nil { - return errorutils.CheckError(err) - } - log.Output(clientUtils.IndentJson(results)) - return nil -} - -func PrintSarif(results *Results, isMultipleRoots, includeLicenses bool) error { - sarifReport, err := GenerateSarifReportFromResults(results, isMultipleRoots, includeLicenses, nil) - if err != nil { - return err - } - sarifFile, err := WriteSarifResultsAsString(sarifReport, false) - if err != nil { - return err - } - log.Output(sarifFile) - return nil -} - -func CheckIfFailBuild(results []services.ScanResponse) bool { - for _, result := range results { - for _, violation := range result.Violations { - if violation.FailBuild { - return true - } - } - } - return false -} - -func IsEmptyScanResponse(results []services.ScanResponse) bool { - for _, result := range results { - if len(result.Violations) > 0 || len(result.Vulnerabilities) > 0 || len(result.Licenses) > 0 { - return false - } - } - return true -} - -func NewFailBuildError() error { - return coreutils.CliError{ExitCode: coreutils.ExitCodeVulnerableBuild, ErrorMsg: "One or more of the violations found are set to fail builds that include them"} -} - -func ToSummary(cmdResult *Results, includeVulnerabilities, includeViolations bool) (summary formats.ResultsSummary) { - if len(cmdResult.ScaResults) <= 1 { - summary.Scans = GetScanSummaryByTargets(cmdResult, includeVulnerabilities, includeViolations) - return - } - for _, scaScan := range cmdResult.ScaResults { - summary.Scans = append(summary.Scans, GetScanSummaryByTargets(cmdResult, includeVulnerabilities, includeViolations, scaScan.Target)...) - } - return -} - -func GetScanSummaryByTargets(r *Results, includeVulnerabilities, includeViolations bool, targets ...string) (summaries []formats.ScanSummary) { - if len(targets) == 0 { - // No filter, one scan summary for all targets - summaries = append(summaries, getScanSummary(includeVulnerabilities, includeViolations, r.ExtendedScanResults, r.ScaResults...)) - return - } - for _, target := range targets { - // Get target sca results - targetScaResults := []*ScaScanResult{} - if targetScaResult := r.getScaScanResultByTarget(target); targetScaResult != nil { - targetScaResults = append(targetScaResults, targetScaResult) - } - // Get target extended results - targetExtendedResults := r.ExtendedScanResults - if targetExtendedResults != nil { - targetExtendedResults = targetExtendedResults.GetResultsForTarget(target) - } - summaries = append(summaries, getScanSummary(includeVulnerabilities, includeViolations, targetExtendedResults, targetScaResults...)) - } - return -} - -func getScanSummary(includeVulnerabilities, includeViolations bool, extendedScanResults *ExtendedScanResults, scaResults ...*ScaScanResult) (summary formats.ScanSummary) { - if len(scaResults) == 1 { - summary.Target = scaResults[0].Target - } - if includeViolations { - summary.Violations = getScanViolationsSummary(extendedScanResults, scaResults...) - } - if includeVulnerabilities { - summary.Vulnerabilities = getScanSecurityVulnerabilitiesSummary(extendedScanResults, scaResults...) - } - return -} - -func getScanViolationsSummary(extendedScanResults *ExtendedScanResults, scaResults ...*ScaScanResult) (violations *formats.ScanViolationsSummary) { - watches := datastructures.MakeSet[string]() - parsed := datastructures.MakeSet[string]() - failBuild := false - scanIds := []string{} - moreInfoUrls := []string{} - violationsUniqueFindings := map[ViolationIssueType]formats.ResultSummary{} - // Parse unique findings - for _, scaResult := range scaResults { - for _, xrayResult := range scaResult.XrayResults { - if xrayResult.ScanId != "" { - scanIds = append(scanIds, xrayResult.ScanId) - } - if xrayResult.XrayDataUrl != "" { - moreInfoUrls = append(moreInfoUrls, xrayResult.XrayDataUrl) - } - for _, violation := range xrayResult.Violations { - watches.Add(violation.WatchName) - failBuild = failBuild || violation.FailBuild - key := violation.IssueId + violation.WatchName - if parsed.Exists(key) { - continue - } - parsed.Add(key) - severity := severityutils.GetSeverity(violation.Severity).String() - violationType := ViolationIssueType(violation.ViolationType) - if _, ok := violationsUniqueFindings[violationType]; !ok { - violationsUniqueFindings[violationType] = formats.ResultSummary{} - } - if _, ok := violationsUniqueFindings[violationType][severity]; !ok { - violationsUniqueFindings[violationType][severity] = map[string]int{} - } - if violationType == ViolationTypeSecurity { - applicableRuns := []*sarif.Run{} - if extendedScanResults != nil { - applicableRuns = append(applicableRuns, extendedScanResults.ApplicabilityScanResults...) - } - violationsUniqueFindings[violationType][severity] = mergeMaps(violationsUniqueFindings[violationType][severity], getSecuritySummaryFindings(violation.Cves, violation.IssueId, violation.Components, applicableRuns...)) - } else { - // License, Operational Risk - violationsUniqueFindings[violationType][severity][formats.NoStatus] += 1 - } - } - } - } - violations = &formats.ScanViolationsSummary{ - Watches: watches.ToSlice(), - FailBuild: failBuild, - ScanResultSummary: formats.ScanResultSummary{ScaResults: &formats.ScaScanResultSummary{ - ScanIds: scanIds, - MoreInfoUrls: moreInfoUrls, - Security: violationsUniqueFindings[ViolationTypeSecurity], - License: violationsUniqueFindings[ViolationTypeLicense], - OperationalRisk: violationsUniqueFindings[ViolationTypeOperationalRisk], - }, - }} - return -} - -func getScanSecurityVulnerabilitiesSummary(extendedScanResults *ExtendedScanResults, scaResults ...*ScaScanResult) (vulnerabilities *formats.ScanResultSummary) { - vulnerabilities = &formats.ScanResultSummary{} - parsed := datastructures.MakeSet[string]() - for _, scaResult := range scaResults { - for _, xrayResult := range scaResult.XrayResults { - if vulnerabilities.ScaResults == nil { - vulnerabilities.ScaResults = &formats.ScaScanResultSummary{Security: formats.ResultSummary{}} - } - if xrayResult.ScanId != "" { - vulnerabilities.ScaResults.ScanIds = append(vulnerabilities.ScaResults.ScanIds, xrayResult.ScanId) - } - if xrayResult.XrayDataUrl != "" { - vulnerabilities.ScaResults.MoreInfoUrls = append(vulnerabilities.ScaResults.MoreInfoUrls, xrayResult.XrayDataUrl) - } - for _, vulnerability := range xrayResult.Vulnerabilities { - if parsed.Exists(vulnerability.IssueId) { - continue - } - parsed.Add(vulnerability.IssueId) - severity := severityutils.GetSeverity(vulnerability.Severity).String() - applicableRuns := []*sarif.Run{} - if extendedScanResults != nil { - applicableRuns = append(applicableRuns, extendedScanResults.ApplicabilityScanResults...) - } - vulnerabilities.ScaResults.Security[severity] = mergeMaps(vulnerabilities.ScaResults.Security[severity], getSecuritySummaryFindings(vulnerability.Cves, vulnerability.IssueId, vulnerability.Components, applicableRuns...)) - } - } - } - if extendedScanResults == nil { - return - } - vulnerabilities.IacResults = getJasSummaryFindings(extendedScanResults.IacScanResults...) - vulnerabilities.SecretsResults = getJasSummaryFindings(extendedScanResults.SecretsScanResults...) - vulnerabilities.SastResults = getJasSummaryFindings(extendedScanResults.SastScanResults...) - return -} - -func getSecuritySummaryFindings(cves []services.Cve, issueId string, components map[string]services.Component, applicableRuns ...*sarif.Run) map[string]int { - uniqueFindings := map[string]int{} - for _, cve := range cves { - applicableStatus := jasutils.NotScanned - if applicableInfo := getCveApplicabilityField(getCveId(cve, issueId), applicableRuns, components); applicableInfo != nil { - applicableStatus = jasutils.ConvertToApplicabilityStatus(applicableInfo.Status) - } - uniqueFindings[applicableStatus.String()] += 1 - } - if len(cves) == 0 { - // XRAY-ID, no scanners for them - status := jasutils.NotScanned - if len(applicableRuns) > 0 { - status = jasutils.NotCovered - } - uniqueFindings[status.String()] += 1 - } - return uniqueFindings -} - -func getCveId(cve services.Cve, defaultIssueId string) string { - if cve.Id == "" { - return defaultIssueId - } - return cve.Id -} - -func mergeMaps(m1, m2 map[string]int) map[string]int { - if m1 == nil { - return m2 - } - for k, v := range m2 { - m1[k] += v - } - return m1 -} - -func getJasSummaryFindings(runs ...*sarif.Run) *formats.ResultSummary { - if len(runs) == 0 { - return nil - } - summary := formats.ResultSummary{} - for _, run := range runs { - for _, result := range run.Results { - resultLevel := sarifutils.GetResultLevel(result) - severity, err := severityutils.ParseSeverity(resultLevel, true) - if err != nil { - log.Warn(fmt.Sprintf("Failed to parse Sarif level %s. %s", resultLevel, err.Error())) - severity = severityutils.Unknown - } - if _, ok := summary[severity.String()]; !ok { - summary[severity.String()] = map[string]int{} - } - summary[severity.String()][formats.NoStatus] += len(result.Locations) - } - } - return &summary -} diff --git a/utils/resultwriter_test.go b/utils/resultwriter_test.go deleted file mode 100644 index d009c777..00000000 --- a/utils/resultwriter_test.go +++ /dev/null @@ -1,865 +0,0 @@ -package utils - -import ( - "fmt" - "os" - "path/filepath" - "sort" - "testing" - - "github.com/jfrog/jfrog-cli-core/v2/utils/tests" - "github.com/jfrog/jfrog-cli-security/formats" - "github.com/jfrog/jfrog-cli-security/formats/sarifutils" - "github.com/jfrog/jfrog-cli-security/utils/jasutils" - "github.com/jfrog/jfrog-cli-security/utils/techutils" - "github.com/jfrog/jfrog-client-go/utils/io/fileutils" - clientTests "github.com/jfrog/jfrog-client-go/utils/tests" - "github.com/jfrog/jfrog-client-go/xray/services" - "github.com/owenrumney/go-sarif/v2/sarif" - "github.com/stretchr/testify/assert" -) - -func TestGetVulnerabilityOrViolationSarifHeadline(t *testing.T) { - assert.Equal(t, "[CVE-2022-1234] loadsh 1.4.1", getXrayIssueSarifHeadline("loadsh", "1.4.1", "CVE-2022-1234")) - assert.NotEqual(t, "[CVE-2022-1234] loadsh 1.4.1", getXrayIssueSarifHeadline("loadsh", "1.2.1", "CVE-2022-1234")) -} - -func TestGetIssueIdentifier(t *testing.T) { - issueId := "XRAY-123456" - cvesRow := []formats.CveRow{{Id: "CVE-2022-1234"}} - assert.Equal(t, "CVE-2022-1234", GetIssueIdentifier(cvesRow, issueId)) - cvesRow = append(cvesRow, formats.CveRow{Id: "CVE-2019-1234"}) - assert.Equal(t, "CVE-2022-1234, CVE-2019-1234", GetIssueIdentifier(cvesRow, issueId)) - assert.Equal(t, issueId, GetIssueIdentifier(nil, issueId)) -} - -func TestGetDirectDependenciesFormatted(t *testing.T) { - testCases := []struct { - name string - directDeps []formats.ComponentRow - expectedOutput string - }{ - { - name: "Single direct dependency", - directDeps: []formats.ComponentRow{ - {Name: "example-package", Version: "1.0.0"}, - }, - expectedOutput: "`example-package 1.0.0`", - }, - { - name: "Multiple direct dependencies", - directDeps: []formats.ComponentRow{ - {Name: "dependency1", Version: "1.0.0"}, - {Name: "dependency2", Version: "2.0.0"}, - }, - expectedOutput: "`dependency1 1.0.0`
`dependency2 2.0.0`", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - output, err := getDirectDependenciesFormatted(tc.directDeps) - assert.NoError(t, err) - assert.Equal(t, tc.expectedOutput, output) - }) - } -} - -func TestGetSarifTableDescription(t *testing.T) { - testCases := []struct { - name string - formattedDeps string - maxCveScore string - status jasutils.ApplicabilityStatus - fixedVersions []string - expectedDescription string - }{ - { - name: "Applicable vulnerability", - formattedDeps: "`example-package 1.0.0`", - maxCveScore: "7.5", - status: "Applicable", - fixedVersions: []string{"1.0.1", "1.0.2"}, - expectedDescription: "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.5 | Applicable | `example-package 1.0.0` | 1.0.1, 1.0.2 |", - }, - { - name: "Not-scanned vulnerability", - formattedDeps: "`example-package 2.0.0`", - maxCveScore: "6.2", - status: "", - fixedVersions: []string{"2.0.1"}, - expectedDescription: "| Severity Score | Direct Dependencies | Fixed Versions |\n| :---: | :----: | :---: |\n| 6.2 | `example-package 2.0.0` | 2.0.1 |", - }, - { - name: "No fixed versions", - formattedDeps: "`example-package 3.0.0`", - maxCveScore: "3.0", - status: "", - fixedVersions: []string{}, - expectedDescription: "| Severity Score | Direct Dependencies | Fixed Versions |\n| :---: | :----: | :---: |\n| 3.0 | `example-package 3.0.0` | No fix available |", - }, - { - name: "Not-covered vulnerability", - formattedDeps: "`example-package 3.0.0`", - maxCveScore: "3.0", - status: "Not covered", - fixedVersions: []string{"3.0.1"}, - expectedDescription: "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.0 | Not covered | `example-package 3.0.0` | 3.0.1 |", - }, - { - name: "Undetermined vulnerability", - formattedDeps: "`example-package 3.0.0`", - maxCveScore: "3.0", - status: "Undetermined", - fixedVersions: []string{"3.0.1"}, - expectedDescription: "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.0 | Undetermined | `example-package 3.0.0` | 3.0.1 |", - }, - { - name: "Not-status vulnerability", - formattedDeps: "`example-package 3.0.0`", - maxCveScore: "3.0", - status: "Not status", - fixedVersions: []string{"3.0.1"}, - expectedDescription: "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.0 | Not status | `example-package 3.0.0` | 3.0.1 |", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - output := getSarifTableDescription(tc.formattedDeps, tc.maxCveScore, tc.status.String(), tc.fixedVersions) - assert.Equal(t, tc.expectedDescription, output) - }) - } -} - -func TestFindMaxCVEScore(t *testing.T) { - testCases := []struct { - name string - cves []formats.CveRow - expectedOutput string - expectedError bool - }{ - { - name: "CVEScore with valid float values", - cves: []formats.CveRow{ - {Id: "CVE-2021-1234", CvssV3: "7.5"}, - {Id: "CVE-2021-5678", CvssV3: "9.2"}, - }, - expectedOutput: "9.2", - }, - { - name: "CVEScore with invalid float value", - cves: []formats.CveRow{ - {Id: "CVE-2022-4321", CvssV3: "invalid"}, - }, - expectedOutput: "", - expectedError: true, - }, - { - name: "CVEScore without values", - cves: []formats.CveRow{}, - expectedOutput: "0.0", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - output, err := findMaxCVEScore(tc.cves) - assert.False(t, tc.expectedError && err == nil) - assert.Equal(t, tc.expectedOutput, output) - }) - } -} - -func TestGetXrayIssueLocationIfValidExists(t *testing.T) { - testDir, cleanup := tests.CreateTempDirWithCallbackAndAssert(t) - defer cleanup() - invocation := sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(testDir)) - file, err := os.Create(filepath.Join(testDir, "go.mod")) - assert.NoError(t, err) - assert.NotNil(t, file) - defer func() { assert.NoError(t, file.Close()) }() - file2, err := os.Create(filepath.Join(testDir, "build.gradle.kts")) - assert.NoError(t, err) - assert.NotNil(t, file2) - defer func() { assert.NoError(t, file2.Close()) }() - - testCases := []struct { - name string - tech techutils.Technology - run *sarif.Run - expectedOutput *sarif.Location - }{ - { - name: "No descriptor information", - tech: techutils.Pip, - run: sarifutils.CreateRunWithDummyResults().WithInvocations([]*sarif.Invocation{invocation}), - expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://Package-Descriptor"))), - }, - { - name: "One descriptor information", - tech: techutils.Go, - run: sarifutils.CreateRunWithDummyResults().WithInvocations([]*sarif.Invocation{invocation}), - expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://" + filepath.Join(testDir, "go.mod")))), - }, - { - name: "One descriptor information - no invocation", - tech: techutils.Go, - run: sarifutils.CreateRunWithDummyResults(), - expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://go.mod"))), - }, - { - name: "Multiple descriptor information", - tech: techutils.Gradle, - run: sarifutils.CreateRunWithDummyResults().WithInvocations([]*sarif.Invocation{invocation}), - expectedOutput: sarif.NewLocation().WithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file://" + filepath.Join(testDir, "build.gradle.kts")))), - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - output, err := getXrayIssueLocationIfValidExists(tc.tech, tc.run) - if assert.NoError(t, err) { - assert.Equal(t, tc.expectedOutput, output) - } - }) - } -} - -func TestConvertXrayScanToSimpleJson(t *testing.T) { - vulnerabilities := []services.Vulnerability{ - { - IssueId: "XRAY-1", - Summary: "summary-1", - Severity: "high", - Components: map[string]services.Component{"component-A": {}, "component-B": {}}, - }, - { - IssueId: "XRAY-2", - Summary: "summary-2", - Severity: "low", - Components: map[string]services.Component{"component-B": {}}, - }, - } - expectedVulnerabilities := []formats.VulnerabilityOrViolationRow{ - { - Summary: "summary-1", - IssueId: "XRAY-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 15}, - ImpactedDependencyName: "component-A", - }, - }, - { - Summary: "summary-1", - IssueId: "XRAY-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 15}, - ImpactedDependencyName: "component-B", - }, - }, - { - Summary: "summary-2", - IssueId: "XRAY-2", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 9}, - ImpactedDependencyName: "component-B", - }, - }, - } - - violations := []services.Violation{ - { - IssueId: "XRAY-1", - Summary: "summary-1", - Severity: "high", - WatchName: "watch-1", - ViolationType: "security", - Components: map[string]services.Component{"component-A": {}, "component-B": {}}, - }, - { - IssueId: "XRAY-2", - Summary: "summary-2", - Severity: "low", - WatchName: "watch-1", - ViolationType: "license", - LicenseKey: "license-1", - Components: map[string]services.Component{"component-B": {}}, - }, - } - expectedSecViolations := []formats.VulnerabilityOrViolationRow{ - { - Summary: "summary-1", - IssueId: "XRAY-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 15}, - ImpactedDependencyName: "component-A", - }, - }, - { - Summary: "summary-1", - IssueId: "XRAY-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 15}, - ImpactedDependencyName: "component-B", - }, - }, - } - expectedLicViolations := []formats.LicenseRow{ - { - LicenseKey: "license-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 9}, - ImpactedDependencyName: "component-B", - }, - }, - } - - licenses := []services.License{ - { - Key: "license-1", - Name: "license-1-name", - Components: map[string]services.Component{"component-A": {}, "component-B": {}}, - }, - { - Key: "license-2", - Name: "license-2-name", - Components: map[string]services.Component{"component-B": {}}, - }, - } - expectedLicenses := []formats.LicenseRow{ - { - LicenseKey: "license-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "component-A"}, - }, - { - LicenseKey: "license-1", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "component-B"}, - }, - { - LicenseKey: "license-2", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "component-B"}, - }, - } - - testCases := []struct { - name string - result services.ScanResponse - includeLicenses bool - allowedLicenses []string - expectedOutput formats.SimpleJsonResults - }{ - { - name: "Vulnerabilities only", - includeLicenses: false, - allowedLicenses: nil, - result: services.ScanResponse{Vulnerabilities: vulnerabilities, Licenses: licenses}, - expectedOutput: formats.SimpleJsonResults{Vulnerabilities: expectedVulnerabilities}, - }, - { - name: "Vulnerabilities with licenses", - includeLicenses: true, - allowedLicenses: nil, - result: services.ScanResponse{Vulnerabilities: vulnerabilities, Licenses: licenses}, - expectedOutput: formats.SimpleJsonResults{Vulnerabilities: expectedVulnerabilities, Licenses: expectedLicenses}, - }, - { - name: "Vulnerabilities only - with allowed licenses", - includeLicenses: false, - allowedLicenses: []string{"license-1"}, - result: services.ScanResponse{Vulnerabilities: vulnerabilities, Licenses: licenses}, - expectedOutput: formats.SimpleJsonResults{ - Vulnerabilities: expectedVulnerabilities, - LicensesViolations: []formats.LicenseRow{ - { - LicenseKey: "license-2", - ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "component-B"}, - }, - }, - }, - }, - { - name: "Violations only", - includeLicenses: false, - allowedLicenses: nil, - result: services.ScanResponse{Violations: violations, Licenses: licenses}, - expectedOutput: formats.SimpleJsonResults{SecurityViolations: expectedSecViolations, LicensesViolations: expectedLicViolations}, - }, - { - name: "Violations - override allowed licenses", - includeLicenses: false, - allowedLicenses: []string{"license-1"}, - result: services.ScanResponse{Violations: violations, Licenses: licenses}, - expectedOutput: formats.SimpleJsonResults{SecurityViolations: expectedSecViolations, LicensesViolations: expectedLicViolations}, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - results := NewAuditResults(SourceCode) - scaScanResult := ScaScanResult{XrayResults: []services.ScanResponse{tc.result}} - results.ScaResults = append(results.ScaResults, &scaScanResult) - output, err := ConvertXrayScanToSimpleJson(results, false, tc.includeLicenses, true, tc.allowedLicenses) - if assert.NoError(t, err) { - assert.ElementsMatch(t, tc.expectedOutput.Vulnerabilities, output.Vulnerabilities) - assert.ElementsMatch(t, tc.expectedOutput.SecurityViolations, output.SecurityViolations) - assert.ElementsMatch(t, tc.expectedOutput.LicensesViolations, output.LicensesViolations) - assert.ElementsMatch(t, tc.expectedOutput.Licenses, output.Licenses) - assert.ElementsMatch(t, tc.expectedOutput.OperationalRiskViolations, output.OperationalRiskViolations) - } - }) - } -} - -func TestJSONMarshall(t *testing.T) { - testCases := []struct { - testName string - resultString string - expectedResult string - }{ - { - testName: "Regular URL", - resultString: "http://my-artifactory.jfrog.io/", - expectedResult: "\"http://my-artifactory.jfrog.io/\"\n", - }, - { - testName: "Regular CVE", - resultString: "CVE-2021-4104", - expectedResult: "\"CVE-2021-4104\"\n", - }, - { - testName: "URL with escape characters ignore rules", - resultString: "https://my-artifactory.jfrog.com/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=1babb2d0-42c0-4389-7770-18a6cab8d9a7\u0026issue_id=XRAY-590941\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=my-watch", - expectedResult: "\"https://my-artifactory.jfrog.com/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=1babb2d0-42c0-4389-7770-18a6cab8d9a7&issue_id=XRAY-590941&on_demand_scanning=true&show_popup=true&type=security&watch_name=my-watch\"\n", - }, - { - testName: "URL with escape characters build scan data", - resultString: "https://my-artifactory.jfrog.com/ui/scans-list/builds-scans/dort1/scan-descendants/1?version=1\u0026package_id=build%3A%2F%2Fdort1\u0026build_repository=artifactory-build-info\u0026component_id=build%3A%2F%2Fshweta1%3A1\u0026page_type=security-vulnerabilities\u0026exposure_status=to_fix", - expectedResult: "\"https://my-artifactory.jfrog.com/ui/scans-list/builds-scans/dort1/scan-descendants/1?version=1&package_id=build%3A%2F%2Fdort1&build_repository=artifactory-build-info&component_id=build%3A%2F%2Fshweta1%3A1&page_type=security-vulnerabilities&exposure_status=to_fix\"\n", - }, - } - - for _, tc := range testCases { - t.Run(tc.testName, func(t *testing.T) { - printedString, err := JSONMarshalNotEscaped(tc.resultString) - assert.NoError(t, err) - assert.Equal(t, tc.expectedResult, string(printedString)) - }) - } -} - -func TestGetSummary(t *testing.T) { - dummyExtendedScanResults := &ExtendedScanResults{ - ApplicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyPassingResult("applic_CVE-2")).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target1")), - }), - }, - SecretsScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("target1/file", 0, 0, 0, 0, "snippet"))).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target1")), - }), - sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("target2/file", 0, 0, 0, 0, "snippet"))).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target2")), - }), - }, - SastScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResults(sarifutils.CreateResultWithLocations("", "", "note", sarifutils.CreateLocation("target1/file2", 0, 0, 0, 0, "snippet"))).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target1")), - }), - }, - } - - expectedVulnerabilities := &formats.ScanResultSummary{ - ScaResults: &formats.ScaScanResultSummary{ - ScanIds: []string{TestScaScanId}, - MoreInfoUrls: []string{TestMoreInfoUrl}, - Security: formats.ResultSummary{ - "Critical": map[string]int{jasutils.ApplicabilityUndetermined.String(): 1}, - "High": map[string]int{jasutils.NotApplicable.String(): 1}, - }, - }, - SecretsResults: &formats.ResultSummary{"Low": map[string]int{jasutils.NotScanned.String(): 2}}, - SastResults: &formats.ResultSummary{"Low": map[string]int{jasutils.NotScanned.String(): 1}}, - } - expectedViolations := &formats.ScanViolationsSummary{ - Watches: []string{"test-watch-name", "test-watch-name2"}, - FailBuild: true, - ScanResultSummary: formats.ScanResultSummary{ - ScaResults: &formats.ScaScanResultSummary{ - ScanIds: []string{TestScaScanId}, - MoreInfoUrls: []string{TestMoreInfoUrl}, - Security: formats.ResultSummary{ - "Critical": map[string]int{jasutils.ApplicabilityUndetermined.String(): 1}, - "High": map[string]int{jasutils.NotApplicable.String(): 1}, - }, - License: formats.ResultSummary{"High": map[string]int{jasutils.NotScanned.String(): 1}}, - }, - }, - } - - testCases := []struct { - name string - results *Results - includeVulnerabilities bool - includeViolations bool - expected formats.ResultsSummary - }{ - { - name: "Vulnerabilities only", - includeVulnerabilities: true, - results: &Results{ - ScaResults: []*ScaScanResult{{ - Target: "target1", - XrayResults: getDummyScaTestResults(true, true), - }}, - ExtendedScanResults: dummyExtendedScanResults, - }, - expected: formats.ResultsSummary{ - Scans: []formats.ScanSummary{{ - Target: "target1", - Vulnerabilities: expectedVulnerabilities, - }}, - }, - }, - { - name: "Violations only", - includeViolations: true, - results: &Results{ - ScaResults: []*ScaScanResult{{ - Target: "target1", - XrayResults: getDummyScaTestResults(true, true), - }}, - ExtendedScanResults: dummyExtendedScanResults, - }, - expected: formats.ResultsSummary{ - Scans: []formats.ScanSummary{{ - Target: "target1", - Violations: expectedViolations, - }}, - }, - }, - { - name: "Vulnerabilities and Violations", - includeVulnerabilities: true, - includeViolations: true, - results: &Results{ - ScaResults: []*ScaScanResult{{ - Target: "target1", - XrayResults: getDummyScaTestResults(true, true), - }}, - ExtendedScanResults: dummyExtendedScanResults, - }, - expected: formats.ResultsSummary{ - Scans: []formats.ScanSummary{{ - Target: "target1", - Violations: expectedViolations, - Vulnerabilities: expectedVulnerabilities, - }}, - }, - }, - } - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - summary := ToSummary(testCase.results, testCase.includeVulnerabilities, testCase.includeViolations) - for _, scan := range summary.Scans { - if scan.Vulnerabilities != nil { - sort.Strings(scan.Vulnerabilities.ScaResults.ScanIds) - sort.Strings(scan.Vulnerabilities.ScaResults.MoreInfoUrls) - } - if scan.Violations != nil { - sort.Strings(scan.Violations.Watches) - sort.Strings(scan.Violations.ScanResultSummary.ScaResults.ScanIds) - sort.Strings(scan.Violations.ScanResultSummary.ScaResults.MoreInfoUrls) - } - } - assert.Equal(t, testCase.expected, summary) - }) - } -} - -func TestGetLayerContentFromComponentId(t *testing.T) { - testCases := []struct { - name string - path string - expectedAlgorithm string - expectedLayerHash string - }{ - { - name: "Valid path", - path: "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", - expectedAlgorithm: "sha256", - expectedLayerHash: "cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e", - }, - { - name: "Invalid path - not hex", - path: "sha256__NOT_HEX.tar", - }, - { - name: "Invalid path - no algorithm", - path: "_cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", - }, - { - name: "Invalid path - no suffix", - path: "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e", - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - algorithm, layerHash := getLayerContentFromComponentId(tc.path) - assert.Equal(t, tc.expectedAlgorithm, algorithm) - assert.Equal(t, tc.expectedLayerHash, layerHash) - }) - } -} - -func preparePatchTestEnv(t *testing.T) (string, string, func()) { - currentWd, err := os.Getwd() - assert.NoError(t, err) - wd, cleanUpTempDir := tests.CreateTempDirWithCallbackAndAssert(t) - cleanUpWd := clientTests.ChangeDirWithCallback(t, currentWd, wd) - dockerfileDir := filepath.Join(wd, "DockerfileDir") - err = fileutils.CreateDirIfNotExist(dockerfileDir) - // Prepare env content - assert.NoError(t, err) - createDummyDockerfile(t, dockerfileDir) - createDummyGithubWorkflow(t, dockerfileDir) - createDummyGithubWorkflow(t, wd) - return wd, dockerfileDir, func() { - cleanUpWd() - cleanUpTempDir() - } -} - -func createDummyGithubWorkflow(t *testing.T, baseDir string) { - assert.NoError(t, fileutils.CreateDirIfNotExist(filepath.Join(baseDir, GithubBaseWorkflowDir))) - assert.NoError(t, os.WriteFile(filepath.Join(baseDir, GithubBaseWorkflowDir, "workflowFile.yml"), []byte("workflow name"), 0644)) -} - -func createDummyDockerfile(t *testing.T, baseDir string) { - assert.NoError(t, os.WriteFile(filepath.Join(baseDir, "Dockerfile"), []byte("Dockerfile data"), 0644)) -} - -func TestPatchRunsToPassIngestionRules(t *testing.T) { - wd, dockerfileDir, cleanUp := preparePatchTestEnv(t) - defer cleanUp() - - testCases := []struct { - name string - cmdResult *Results - subScan SubScanType - withEnvVars bool - withDockerfile bool - input []*sarif.Run - expectedResults []*sarif.Run - }{ - { - name: "No runs", - cmdResult: &Results{ResultType: DockerImage, ScaResults: []*ScaScanResult{{Name: "dockerImage:imageVersion"}}}, - subScan: SecretsScan, - input: []*sarif.Run{}, - expectedResults: []*sarif.Run{}, - }, - { - name: "Build scan - SCA", - cmdResult: &Results{ResultType: Build, ScaResults: []*ScaScanResult{{Name: "buildName (buildNumber)"}}}, - subScan: ScaScan, - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultsInWd(wd, sarifutils.CreateDummyResultInPath(fmt.Sprintf("file://%s", filepath.Join(wd, "dir", "file")))), - }, - expectedResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultsInWd(wd, sarifutils.CreateDummyResultInPath(filepath.Join("dir", "file"))), - }, - }, - { - name: "Docker image scan - SCA", - cmdResult: &Results{ResultType: DockerImage, ScaResults: []*ScaScanResult{{Name: "dockerImage:imageVersion"}}}, - subScan: ScaScan, - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg"))). - WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd)), - }, - ), - sarifutils.CreateRunWithDummyResultsInWd(wd, - sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg")), - ), - }, - expectedResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", - sarifutils.CreateDummyResultWithFingerprint("some-msg\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "some-msg", jfrogFingerprintAlgorithmName, "9522c1d915eef55b4a0dc9e160bf5dc7", - sarifutils.CreateDummyLocationWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256"), - ), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd)), - }), - sarifutils.CreateRunWithDummyResultsInWd(wd, - sarifutils.CreateDummyResultWithFingerprint("some-msg\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "some-msg", jfrogFingerprintAlgorithmName, "9522c1d915eef55b4a0dc9e160bf5dc7", - sarifutils.CreateDummyLocationWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256"), - ), - ), - }, - }, - { - name: "Docker image scan - with env vars", - cmdResult: &Results{ResultType: DockerImage, ScaResults: []*ScaScanResult{{Name: "dockerImage:imageVersion"}}}, - subScan: ScaScan, - withEnvVars: true, - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultsInWd(wd, - sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg")), - // No location, should be removed in the output - sarifutils.CreateDummyResult("some-markdown", "some-other-msg", "rule", "level"), - ), - }, - expectedResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultsInWd(wd, - sarifutils.CreateDummyResultWithFingerprint(fmt.Sprintf("some-msg\nGithub Actions Workflow: %s\nRun: 123\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", filepath.Join(GithubBaseWorkflowDir, "workflowFile.yml")), "some-msg", jfrogFingerprintAlgorithmName, "eda26ae830c578197aeda65a82d7f093", - sarifutils.CreateDummyLocationWithPathAndLogicalLocation("", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithPhysicalLocation( - sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewSimpleArtifactLocation(filepath.Join(GithubBaseWorkflowDir, "workflowFile.yml"))), - ), - ), - ), - }, - }, - { - name: "Docker image scan - with Dockerfile in wd", - cmdResult: &Results{ResultType: DockerImage, ScaResults: []*ScaScanResult{{Name: "dockerImage:imageVersion"}}}, - subScan: ScaScan, - withEnvVars: true, - withDockerfile: true, - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultsInWd(dockerfileDir, - sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg")), - ), - }, - expectedResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultsInWd(dockerfileDir, - sarifutils.CreateDummyResultWithFingerprint(fmt.Sprintf("some-msg\nGithub Actions Workflow: %s\nRun: 123\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", filepath.Join(GithubBaseWorkflowDir, "workflowFile.yml")), "some-msg", jfrogFingerprintAlgorithmName, "8cbd7268a4d20f2358ba2667ebd18956", - sarifutils.CreateDummyLocationWithPathAndLogicalLocation("", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithPhysicalLocation( - sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewSimpleArtifactLocation("Dockerfile")), - ), - ), - ), - }, - }, - { - name: "Docker image scan - Secrets", - cmdResult: &Results{ResultType: DockerImage, ScaResults: []*ScaScanResult{{Name: "dockerImage:imageVersion"}}}, - subScan: SecretsScan, - input: []*sarif.Run{ - sarifutils.CreateRunNameWithResults("some tool name", - sarifutils.CreateDummyResultInPath(fmt.Sprintf("file://%s", filepath.Join(wd, "unpacked", "filesystem", "blobs", "sha1", "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", "usr", "src", "app", "server", "index.js"))), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd)), - }), - }, - expectedResults: []*sarif.Run{ - { - Tool: sarif.Tool{ - Driver: sarifutils.CreateDummyDriver(patchedBinarySecretScannerToolName, "", &sarif.ReportingDescriptor{ - ID: "rule", - ShortDescription: sarif.NewMultiformatMessageString("[Secret in Binary found] "), - }), - }, - Invocations: []*sarif.Invocation{sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd))}, - Results: []*sarif.Result{ - sarifutils.CreateDummyResultWithFingerprint(fmt.Sprintf("🔒 Found Secrets in Binary docker scanning:\nImage: dockerImage:imageVersion\nLayer (sha1): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: %s\nEvidence: snippet", filepath.Join("usr", "src", "app", "server", "index.js")), "", jfrogFingerprintAlgorithmName, "dee156c9fd75a4237102dc8fb29277a2", - sarifutils.CreateDummyLocationWithPathAndLogicalLocation(filepath.Join("usr", "src", "app", "server", "index.js"), "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", "layer", "algorithm", "sha1"), - ), - }, - }, - }, - }, - { - name: "Binary scan - SCA", - cmdResult: &Results{ResultType: Binary, ScaResults: []*ScaScanResult{{Target: filepath.Join(wd, "dir", "binary")}}}, - subScan: ScaScan, - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultsInWd(wd, - sarifutils.CreateDummyResultInPath(fmt.Sprintf("file://%s", filepath.Join(wd, "dir", "binary"))), - ), - }, - expectedResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultsInWd(wd, - sarifutils.CreateDummyResultWithFingerprint("", "", jfrogFingerprintAlgorithmName, "e72a936dc73acbc4283a93230ff9b6e8", sarifutils.CreateDummyLocationInPath(filepath.Join("dir", "binary"))), - ), - }, - }, - { - name: "Audit scan - SCA", - cmdResult: &Results{ResultType: SourceCode, ScaResults: []*ScaScanResult{{Target: wd}}}, - subScan: ScaScan, - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultsInWd(wd, - sarifutils.CreateDummyResultInPath(filepath.Join(wd, "Package-Descriptor")), - // No location, should be removed in the output - sarifutils.CreateDummyResult("some-markdown", "some-other-msg", "rule", "level"), - ), - }, - expectedResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultsInWd(wd, - sarifutils.CreateDummyResultInPath("Package-Descriptor"), - ), - }, - }, - { - name: "Audit scan - Secrets", - cmdResult: &Results{ResultType: SourceCode, ScaResults: []*ScaScanResult{{Target: wd}}}, - subScan: SecretsScan, - input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultsInWd(wd, - sarifutils.CreateDummyResultInPath(fmt.Sprintf("file://%s", filepath.Join(wd, "dir", "file"))), - // No location, should be removed in the output - sarifutils.CreateDummyResult("some-markdown", "some-other-msg", "rule", "level"), - ), - }, - expectedResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultsInWd(wd, - sarifutils.CreateDummyResultInPath(filepath.Join("dir", "file")), - ), - }, - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - if tc.withEnvVars { - cleanFileEnv := clientTests.SetEnvWithCallbackAndAssert(t, CurrentWorkflowNameEnvVar, "workflow name") - defer cleanFileEnv() - cleanRunNumEnv := clientTests.SetEnvWithCallbackAndAssert(t, CurrentWorkflowRunNumberEnvVar, "123") - defer cleanRunNumEnv() - } else { - // Since the the env are provided by the - cleanFileEnv := clientTests.SetEnvWithCallbackAndAssert(t, CurrentWorkflowNameEnvVar, "") - defer cleanFileEnv() - cleanRunNumEnv := clientTests.SetEnvWithCallbackAndAssert(t, CurrentWorkflowRunNumberEnvVar, "") - defer cleanRunNumEnv() - } - if tc.withDockerfile { - revertWd := clientTests.ChangeDirWithCallback(t, wd, dockerfileDir) - defer revertWd() - } - patchRunsToPassIngestionRules(tc.subScan, tc.cmdResult, tc.input...) - assert.ElementsMatch(t, tc.expectedResults, tc.input) - }) - } -} - -func getDummyScaTestResults(vulnerability, violation bool) (responses []services.ScanResponse) { - response := services.ScanResponse{} - if vulnerability { - response.Vulnerabilities = []services.Vulnerability{ - {IssueId: "XRAY-1", Severity: "Critical", Cves: []services.Cve{{Id: "CVE-1"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, - {IssueId: "XRAY-2", Severity: "High", Cves: []services.Cve{{Id: "CVE-2"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, - } - } - if violation { - response.Violations = []services.Violation{ - {ViolationType: ViolationTypeSecurity.String(), WatchName: "test-watch-name", IssueId: "XRAY-1", Severity: "Critical", Cves: []services.Cve{{Id: "CVE-1"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, - {ViolationType: ViolationTypeSecurity.String(), FailBuild: true, WatchName: "test-watch-name", IssueId: "XRAY-2", Severity: "High", Cves: []services.Cve{{Id: "CVE-2"}}, Components: map[string]services.Component{"issueId_direct_dependency": {}}}, - {ViolationType: ViolationTypeLicense.String(), WatchName: "test-watch-name2", IssueId: "MIT", Severity: "High", LicenseKey: "MIT", Components: map[string]services.Component{"issueId_direct_dependency": {}}}, - } - } - response.ScanId = TestScaScanId - response.XrayDataUrl = TestMoreInfoUrl - responses = append(responses, response) - return -} diff --git a/utils/utils.go b/utils/utils.go index 7629bbbb..4fd95e87 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -1,23 +1,25 @@ package utils import ( + "bytes" "crypto" "encoding/hex" - "bytes" "encoding/json" "fmt" + "os" "strings" "github.com/jfrog/gofrog/datastructures" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-client-go/utils/errorutils" ) const ( - NodeModulesPattern = "**/*node_modules*/**" - JfMsiEnvVariable = "JF_MSI" + NodeModulesPattern = "**/*node_modules*/**" + JfMsiEnvVariable = "JF_MSI" - BaseDocumentationURL = "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/" - JasInfoURL = "https://jfrog.com/xray/" + BaseDocumentationURL = "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/" + JasInfoURL = "https://jfrog.com/xray/" EntitlementsMinVersion = "3.66.5" ) @@ -71,20 +73,27 @@ func GetAllSupportedScans() []SubScanType { return []SubScanType{ScaScan, ContextualAnalysisScan, IacScan, SastScan, SecretsScan} } -// UniqueUnion returns a new slice of strings that contains elements from both input slices without duplicates -func UniqueUnion[T comparable](arr []T, others ...T) []T { - uniqueSet := datastructures.MakeSet[T]() - var result []T - for _, str := range arr { - uniqueSet.Add(str) - result = append(result, str) - } - for _, str := range others { - if exist := uniqueSet.Exists(str); !exist { - result = append(result, str) +func IsCI() bool { + return strings.ToLower(os.Getenv(coreutils.CI)) == "true" +} + +// UniqueIntersection returns a new slice of strings that contains elements from both input slices without duplicates +func UniqueIntersection[T comparable](arr []T, others ...T) []T { + uniqueSet := datastructures.MakeSetFromElements(arr...) + uniqueIntersection := datastructures.MakeSet[T]() + for _, other := range others { + if exist := uniqueSet.Exists(other); exist { + uniqueIntersection.Add(other) } } - return result + return uniqueIntersection.ToSlice() +} + +// UniqueUnion returns a new slice of strings that contains elements from the input slice and the elements provided without duplicates +func UniqueUnion[T comparable](arr []T, elements ...T) []T { + uniqueSet := datastructures.MakeSetFromElements(arr...) + uniqueSet.AddElements(elements...) + return uniqueSet.ToSlice() } func GetAsJsonBytes(output interface{}, escapeValues, indent bool) (results []byte, err error) { diff --git a/utils/utils_test.go b/utils/utils_test.go index a7e0c1b6..7629efe1 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -6,6 +6,72 @@ import ( "github.com/stretchr/testify/assert" ) +func TestUniqueIntersection(t *testing.T) { + testCases := []struct { + name string + slice1 []string + slice2 []string + expected []string + }{ + { + name: "Empty", + slice1: []string{}, + slice2: []string{}, + expected: []string{}, + }, + { + name: "One element", + slice1: []string{"element1"}, + slice2: []string{"element1"}, + expected: []string{"element1"}, + }, + { + name: "Two elements", + slice1: []string{"element1", "element2"}, + slice2: []string{"element2", "element3"}, + expected: []string{"element2"}, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + assert.ElementsMatch(t, tc.expected, UniqueIntersection(tc.slice1, tc.slice2...)) + }) + } +} + +func TestUniqueUnion(t *testing.T) { + testCases := []struct { + name string + slice []string + elements []string + expected []string + }{ + { + name: "Empty", + slice: []string{}, + elements: []string{}, + expected: []string{}, + }, + { + name: "One element", + slice: []string{"element1"}, + elements: []string{"element1"}, + expected: []string{"element1"}, + }, + { + name: "Two elements", + slice: []string{"element1", "element2"}, + elements: []string{"element2", "element3"}, + expected: []string{"element1", "element2", "element3"}, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + assert.ElementsMatch(t, tc.expected, UniqueUnion(tc.slice, tc.elements...)) + }) + } +} + func TestToCommandEnvVars(t *testing.T) { testCases := []struct { name string diff --git a/utils/validations/test_mocks.go b/utils/validations/test_mocks.go index b0d1d6cf..a5726b7c 100644 --- a/utils/validations/test_mocks.go +++ b/utils/validations/test_mocks.go @@ -13,11 +13,18 @@ import ( ) const ( - TestMsi = "27e175b8-e525-11ee-842b-7aa2c69b8f1f" - TestScaScanId = "3d90ec4b-cf33-4846-6831-4bf9576f2235" - TestMoreInfoUrl = "https://www.jfrog.com" + TestMsi = "27e175b8-e525-11ee-842b-7aa2c69b8f1f" + TestScaScanId = "3d90ec4b-cf33-4846-6831-4bf9576f2235" + + // TestMoreInfoUrl = "https://www.jfrog.com" + TestPlatformUrl = "https://test-platform-url.jfrog.io/" + TestMoreInfoUrl = "https://test-more-info-url.jfrog.io/" + TestConfigProfileName = "default-profile" - versionApiUrl = "/%s/api/v1/system/version" +) + +var ( + versionApiUrl = "/%s/api/v1/system/version" ) type restsTestHandler func(w http.ResponseWriter, r *http.Request) diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index 011f942b..57db57d4 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -25,11 +25,11 @@ func VerifySarifResults(t *testing.T, content string, params ValidationParams) { func ValidateCommandSarifOutput(t *testing.T, params ValidationParams) { results, ok := params.Actual.(*sarif.Report) - if assert.True(t, ok) { + if assert.True(t, ok, "Actual content is not a *sarif.Report") { ValidateSarifIssuesCount(t, params, results) if params.Expected != nil { expectedResults, ok := params.Expected.(*sarif.Report) - if assert.True(t, ok) { + if assert.True(t, ok, "Expected content is not a *sarif.Report") { ValidateSarifResults(t, params.ExactResultsMatch, expectedResults, results) } } @@ -43,7 +43,7 @@ func ValidateSarifIssuesCount(t *testing.T, params ValidationParams, results *sa secrets := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, sarifparser.SecretsToolName)...) sast := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, sarifparser.SastToolName)...) - scaRuns := sarifutils.GetRunsByToolName(results, sarifparser.ScaToolName) + scaRuns := sarifutils.GetRunsByToolName(results, sarifparser.ScaScannerToolName) for _, run := range scaRuns { for _, result := range run.Results { // If watch property exists, add to security violations or license violations else add to vulnerabilities @@ -52,12 +52,10 @@ func ValidateSarifIssuesCount(t *testing.T, params ValidationParams, results *sa securityViolations++ } else { licenseViolations++ - // No more work needed for license violations - continue } - } else { - vulnerabilities++ + continue } + vulnerabilities++ // Get the applicability status in the result properties (convert to string) and add count to the appropriate category applicabilityProperty := result.Properties[jasutils.ApplicabilitySarifPropertyKey] if applicability, ok := applicabilityProperty.(string); ok { @@ -76,26 +74,26 @@ func ValidateSarifIssuesCount(t *testing.T, params ValidationParams, results *sa } if params.ExactResultsMatch { - assert.Equal(t, params.Sast, sast, "Expected %d sast in scan responses, but got %d sast.", params.Sast, sast) - assert.Equal(t, params.Secrets, secrets, "Expected %d secrets in scan responses, but got %d secrets.", params.Secrets, secrets) - assert.Equal(t, params.Iac, iac, "Expected %d IaC in scan responses, but got %d IaC.", params.Iac, iac) - assert.Equal(t, params.Applicable, applicableResults, "Expected %d applicable results in scan responses, but got %d applicable results.", params.Applicable, applicableResults) - assert.Equal(t, params.Undetermined, undeterminedResults, "Expected %d undetermined results in scan responses, but got %d undetermined results.", params.Undetermined, undeterminedResults) - assert.Equal(t, params.NotCovered, notCoveredResults, "Expected %d not covered results in scan responses, but got %d not covered results.", params.NotCovered, notCoveredResults) - assert.Equal(t, params.NotApplicable, notApplicableResults, "Expected %d not applicable results in scan responses, but got %d not applicable results.", params.NotApplicable, notApplicableResults) - assert.Equal(t, params.SecurityViolations, securityViolations, "Expected %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, securityViolations) - assert.Equal(t, params.LicenseViolations, licenseViolations, "Expected %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, licenseViolations) - assert.Equal(t, params.Vulnerabilities, vulnerabilities, "Expected %d vulnerabilities in scan responses, but got %d vulnerabilities.", params.Vulnerabilities, vulnerabilities) + assert.Equal(t, params.Sast, sast, GetValidationCountErrMsg("sast", "sarif report", true, params.Sast, sast)) + assert.Equal(t, params.Secrets, secrets, GetValidationCountErrMsg("secrets", "sarif report", true, params.Secrets, secrets)) + assert.Equal(t, params.Iac, iac, GetValidationCountErrMsg("Iac", "sarif report", true, params.Iac, iac)) + assert.Equal(t, params.Applicable, applicableResults, "Expected %d applicable results in sarif report, but got %d applicable results.", params.Applicable, applicableResults) + assert.Equal(t, params.Undetermined, undeterminedResults, "Expected %d undetermined results in sarif report, but got %d undetermined results.", params.Undetermined, undeterminedResults) + assert.Equal(t, params.NotCovered, notCoveredResults, "Expected %d not covered results in sarif report, but got %d not covered results.", params.NotCovered, notCoveredResults) + assert.Equal(t, params.NotApplicable, notApplicableResults, "Expected %d not applicable results in sarif report, but got %d not applicable results.", params.NotApplicable, notApplicableResults) + assert.Equal(t, params.SecurityViolations, securityViolations, "Expected %d security violations in sarif report, but got %d security violations.", params.SecurityViolations, securityViolations) + assert.Equal(t, params.LicenseViolations, licenseViolations, "Expected %d license violations in sarif report, but got %d license violations.", params.LicenseViolations, licenseViolations) + assert.Equal(t, params.Vulnerabilities, vulnerabilities, "Expected %d vulnerabilities in sarif report, but got %d vulnerabilities.", params.Vulnerabilities, vulnerabilities) } else { - assert.GreaterOrEqual(t, sast, params.Sast, "Expected at least %d sast in scan responses, but got %d sast.", params.Sast, sast) - assert.GreaterOrEqual(t, secrets, params.Secrets, "Expected at least %d secrets in scan responses, but got %d secrets.", params.Secrets, secrets) - assert.GreaterOrEqual(t, iac, params.Iac, "Expected at least %d IaC in scan responses, but got %d IaC.", params.Iac, iac) - assert.GreaterOrEqual(t, applicableResults, params.Applicable, "Expected at least %d applicable results in scan responses, but got %d applicable results.", params.Applicable, applicableResults) - assert.GreaterOrEqual(t, undeterminedResults, params.Undetermined, "Expected at least %d undetermined results in scan responses, but got %d undetermined results.", params.Undetermined, undeterminedResults) - assert.GreaterOrEqual(t, notCoveredResults, params.NotCovered, "Expected at least %d not covered results in scan responses, but got %d not covered results.", params.NotCovered, notCoveredResults) - assert.GreaterOrEqual(t, notApplicableResults, params.NotApplicable, "Expected at least %d not applicable results in scan responses, but got %d not applicable results.", params.NotApplicable, notApplicableResults) - assert.GreaterOrEqual(t, securityViolations, params.SecurityViolations, "Expected at least %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, securityViolations) - assert.GreaterOrEqual(t, licenseViolations, params.LicenseViolations, "Expected at least %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, licenseViolations) + assert.GreaterOrEqual(t, sast, params.Sast, "Expected at least %d sast in sarif report, but got %d sast.", params.Sast, sast) + assert.GreaterOrEqual(t, secrets, params.Secrets, "Expected at least %d secrets in sarif report, but got %d secrets.", params.Secrets, secrets) + assert.GreaterOrEqual(t, iac, params.Iac, "Expected at least %d IaC in sarif report, but got %d IaC.", params.Iac, iac) + assert.GreaterOrEqual(t, applicableResults, params.Applicable, "Expected at least %d applicable results in sarif report, but got %d applicable results.", params.Applicable, applicableResults) + assert.GreaterOrEqual(t, undeterminedResults, params.Undetermined, "Expected at least %d undetermined results in sarif report, but got %d undetermined results.", params.Undetermined, undeterminedResults) + assert.GreaterOrEqual(t, notCoveredResults, params.NotCovered, "Expected at least %d not covered results in sarif report, but got %d not covered results.", params.NotCovered, notCoveredResults) + assert.GreaterOrEqual(t, notApplicableResults, params.NotApplicable, "Expected at least %d not applicable results in sarif report, but got %d not applicable results.", params.NotApplicable, notApplicableResults) + assert.GreaterOrEqual(t, securityViolations, params.SecurityViolations, "Expected at least %d security violations in sarif report, but got %d security violations.", params.SecurityViolations, securityViolations) + assert.GreaterOrEqual(t, licenseViolations, params.LicenseViolations, "Expected at least %d license violations in sarif report, but got %d license violations.", params.LicenseViolations, licenseViolations) } } @@ -183,7 +181,7 @@ func getResultByResultId(expected *sarif.Result, actual []*sarif.Result) *sarif. } func isPotentialSimilarResults(expected, actual *sarif.Result) bool { - return sarifutils.GetResultRuleId(actual) == sarifutils.GetResultRuleId(expected) && sarifutils.GetResultMsgText(actual) == sarifutils.GetResultMsgText(expected) + return sarifutils.GetResultRuleId(actual) == sarifutils.GetResultRuleId(expected) && sarifutils.GetResultMsgText(actual) == sarifutils.GetResultMsgText(expected) && sarifutils.GetResultProperty(sarifparser.WatchSarifPropertyKey, actual) == sarifutils.GetResultProperty(sarifparser.WatchSarifPropertyKey, expected) } func hasSameLocations(expected, actual *sarif.Result) bool { diff --git a/utils/validations/test_validate_sca.go b/utils/validations/test_validate_sca.go index bed0b7ec..53289bd7 100644 --- a/utils/validations/test_validate_sca.go +++ b/utils/validations/test_validate_sca.go @@ -5,7 +5,7 @@ import ( "fmt" "testing" - "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-client-go/xray/services" "github.com/stretchr/testify/assert" ) @@ -25,11 +25,11 @@ func VerifyJsonResults(t *testing.T, content string, params ValidationParams) { // Actual (and optional Expected) content should be a slice of services.ScanResponse in the validation params func ValidateCommandJsonOutput(t *testing.T, params ValidationParams) { results, ok := params.Actual.([]services.ScanResponse) - if assert.True(t, ok) { + if assert.True(t, ok, "Actual content is not a slice of services.ScanResponse") { ValidateScanResponseIssuesCount(t, params, results...) if params.Expected != nil { expectedResults, ok := params.Expected.([]services.ScanResponse) - if assert.True(t, ok) { + if assert.True(t, ok, "Expected content is not a slice of services.ScanResponse") { ValidateScanResponses(t, params.ExactResultsMatch, expectedResults, results) } } @@ -47,11 +47,11 @@ func ValidateScanResponseIssuesCount(t *testing.T, params ValidationParams, cont licenses = append(licenses, result.Licenses...) for _, violation := range result.Violations { switch violation.ViolationType { - case formats.ViolationTypeSecurity.String(): + case utils.ViolationTypeSecurity.String(): securityViolations = append(securityViolations, violation) - case formats.ViolationTypeLicense.String(): + case utils.ViolationTypeLicense.String(): licenseViolations = append(licenseViolations, violation) - case formats.ViolationTypeOperationalRisk.String(): + case utils.ViolationTypeOperationalRisk.String(): operationalViolations = append(operationalViolations, violation) } } diff --git a/utils/validations/test_validate_simple_json.go b/utils/validations/test_validate_simple_json.go index 52697f65..3902e176 100644 --- a/utils/validations/test_validate_simple_json.go +++ b/utils/validations/test_validate_simple_json.go @@ -15,18 +15,19 @@ import ( func VerifySimpleJsonResults(t *testing.T, content string, params ValidationParams) { var results formats.SimpleJsonResults err := json.Unmarshal([]byte(content), &results) - assert.NoError(t, err) + assert.NoError(t, err, "Failed to unmarshal content to formats.SimpleJsonResults") params.Actual = results ValidateCommandSimpleJsonOutput(t, params) } +// ValidateCommandSimpleJsonOutput validates SimpleJsonResults results. params.Actual (and params.Expected if provided) should be of type formats.SimpleJsonResults func ValidateCommandSimpleJsonOutput(t *testing.T, params ValidationParams) { results, ok := params.Actual.(formats.SimpleJsonResults) - if assert.True(t, ok) { + if assert.True(t, ok, "Actual content is not of type formats.SimpleJsonResults") { ValidateSimpleJsonIssuesCount(t, params, results) if params.Expected != nil { expectedResults, ok := params.Expected.(formats.SimpleJsonResults) - if assert.True(t, ok) { + if assert.True(t, ok, "Expected content is not of type formats.SimpleJsonResults") { ValidateSimpleJsonResults(t, params.ExactResultsMatch, expectedResults, results) } } diff --git a/utils/validations/test_validate_summary.go b/utils/validations/test_validate_summary.go index 776e2133..112a1f2e 100644 --- a/utils/validations/test_validate_summary.go +++ b/utils/validations/test_validate_summary.go @@ -12,7 +12,7 @@ import ( // Content should be a Json string of formats.SummaryResults and will be unmarshal. // Value is set as the Actual content in the validation params func VerifySummaryResults(t *testing.T, content string, params ValidationParams) { - var results formats.SummaryResults + var results formats.ResultsSummary err := json.Unmarshal([]byte(content), &results) assert.NoError(t, err) params.Actual = results @@ -20,20 +20,29 @@ func VerifySummaryResults(t *testing.T, content string, params ValidationParams) } func ValidateCommandSummaryOutput(t *testing.T, params ValidationParams) { - results, ok := params.Actual.(formats.SummaryResults) - if assert.True(t, ok) { + results, ok := params.Actual.(formats.ResultsSummary) + if assert.True(t, ok, "Actual content is not a formats.ResultsSummary") { ValidateSummaryIssuesCount(t, params, results) } } -func ValidateSummaryIssuesCount(t *testing.T, params ValidationParams, results formats.SummaryResults) { +func ValidateSummaryIssuesCount(t *testing.T, params ValidationParams, results formats.ResultsSummary) { var vulnerabilities, securityViolations, licenseViolations, opRiskViolations, applicableResults, undeterminedResults, notCoveredResults, notApplicableResults, sast, iac, secrets int + + vulnerabilities = results.GetTotalVulnerabilities() + + securityViolations = results.GetTotalViolations(formats.ScaSecurityResult) + licenseViolations = results.GetTotalViolations(formats.ScaLicenseResult) + opRiskViolations = results.GetTotalViolations(formats.ScaOperationalResult) + // Jas Results only available as vulnerabilities + sast = results.GetTotalVulnerabilities(formats.SastResult) + secrets = results.GetTotalVulnerabilities(formats.SecretsResult) + iac = results.GetTotalVulnerabilities(formats.IacResult) + // Get applicability status counts for _, scan := range results.Scans { - // Vulnerabilities if scan.Vulnerabilities != nil { - if scan.Vulnerabilities.ScaScanResults != nil { - vulnerabilities += scan.Vulnerabilities.ScaScanResults.SummaryCount.GetTotal() - for _, counts := range scan.Vulnerabilities.ScaScanResults.SummaryCount { + if scan.Vulnerabilities.ScaResults != nil { + for _, counts := range scan.Vulnerabilities.ScaResults.Security { for status, count := range counts { switch status { case jasutils.Applicable.String(): @@ -48,23 +57,12 @@ func ValidateSummaryIssuesCount(t *testing.T, params ValidationParams, results f } } } - if scan.Vulnerabilities.SastScanResults != nil { - sast += scan.Vulnerabilities.SastScanResults.GetTotal() - } - if scan.Vulnerabilities.SecretsScanResults != nil { - secrets += scan.Vulnerabilities.SecretsScanResults.GetTotal() - } - if scan.Vulnerabilities.IacScanResults != nil { - iac += scan.Vulnerabilities.IacScanResults.GetTotal() - } } - // Violations - securityViolations += scan.Violations[formats.ViolationTypeSecurity.String()].GetTotal() - licenseViolations += scan.Violations[formats.ViolationTypeLicense.String()].GetTotal() - opRiskViolations += scan.Violations[formats.ViolationTypeOperationalRisk.String()].GetTotal() } - + // validate the counts if params.ExactResultsMatch { + assert.Equal(t, params.Vulnerabilities, vulnerabilities, "Expected %d vulnerabilities in scan responses, but got %d vulnerabilities.", params.Vulnerabilities, vulnerabilities) + assert.Equal(t, params.Sast, sast, "Expected %d sast in scan responses, but got %d sast.", params.Sast, sast) assert.Equal(t, params.Secrets, secrets, "Expected %d secrets in scan responses, but got %d secrets.", params.Secrets, secrets) assert.Equal(t, params.Iac, iac, "Expected %d IaC in scan responses, but got %d IaC.", params.Iac, iac) @@ -79,6 +77,8 @@ func ValidateSummaryIssuesCount(t *testing.T, params ValidationParams, results f assert.Equal(t, params.OperationalViolations, opRiskViolations, "Expected %d operational risk violations in scan responses, but got %d operational risk violations.", params.OperationalViolations, opRiskViolations) return } + assert.GreaterOrEqual(t, vulnerabilities, params.Vulnerabilities, "Expected at least %d vulnerabilities in scan responses, but got %d vulnerabilities.", params.Vulnerabilities, vulnerabilities) + assert.GreaterOrEqual(t, sast, params.Sast, "Expected at least %d sast in scan responses, but got %d sast.", params.Sast, sast) assert.GreaterOrEqual(t, secrets, params.Secrets, "Expected at least %d secrets in scan responses, but got %d secrets.", params.Secrets, secrets) assert.GreaterOrEqual(t, iac, params.Iac, "Expected at least %d IaC in scan responses, but got %d IaC.", params.Iac, iac) diff --git a/utils/validations/test_validation.go b/utils/validations/test_validation.go index d2534127..d093e4b9 100644 --- a/utils/validations/test_validation.go +++ b/utils/validations/test_validation.go @@ -9,6 +9,17 @@ import ( "github.com/jfrog/jfrog-cli-security/utils" ) +const ( + ErrCountFormat = "Expected%s %d %s in %s, but got %d %s." +) + +func GetValidationCountErrMsg(what, where string, exactMatch bool, expectedCount, actualCount int) string { + if exactMatch { + return fmt.Sprintf(ErrCountFormat, "", expectedCount, what, where, actualCount, what) + } + return fmt.Sprintf(ErrCountFormat, " at least", expectedCount, what, where, actualCount, what) +} + type ValidationParams struct { // The actual content to verify. Actual interface{} diff --git a/utils/xsc/analyticsmetrics.go b/utils/xsc/analyticsmetrics.go index 2a67b6e2..ed8fd13b 100644 --- a/utils/xsc/analyticsmetrics.go +++ b/utils/xsc/analyticsmetrics.go @@ -164,13 +164,20 @@ func (ams *AnalyticsMetricsService) CreateXscAnalyticsGeneralEventFinalizeFromAu if auditResults.GetErrors() != nil { eventStatus = xscservices.Failed } - summary, err := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{}).ConvertToSummary(auditResults) + summary, err := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{IncludeVulnerabilities: true, HasViolationContext: true}).ConvertToSummary(auditResults) if err != nil { log.Warn(fmt.Sprintf("Failed to convert audit results to summary. %s", err.Error())) } + totalFindings := 0 + if summary.HasViolations() { + totalFindings = summary.GetTotalViolations() + } else { + totalFindings = summary.GetTotalVulnerabilities() + } + // return summary.GetTotalVulnerabilities() basicEvent := xscservices.XscAnalyticsBasicGeneralEvent{ EventStatus: eventStatus, - TotalFindings: auditResults.CountScanResultsFindings(true, true), + TotalFindings: totalFindings, TotalScanDuration: totalDuration.String(), } return &xscservices.XscAnalyticsGeneralEventFinalize{ diff --git a/utils/xsc/analyticsmetrics_test.go b/utils/xsc/analyticsmetrics_test.go index 3574c424..aca3198f 100644 --- a/utils/xsc/analyticsmetrics_test.go +++ b/utils/xsc/analyticsmetrics_test.go @@ -109,7 +109,7 @@ func TestAnalyticsMetricsService_createAuditResultsFromXscAnalyticsBasicGeneralE func getDummyContentForGeneralEvent(withJas, withErr bool) *results.SecurityCommandResults { vulnerabilities := []services.Vulnerability{{IssueId: "XRAY-ID", Severity: "medium", Cves: []services.Cve{{Id: "CVE-123"}}, Components: map[string]services.Component{"issueId_2_direct_dependency": {}}}} - cmdResults := results.NewCommandResults("", true) + cmdResults := results.NewCommandResults(utils.SourceCode, "", true) scanResults := cmdResults.NewScanResults(results.ScanTarget{Target: "target"}) scanResults.NewScaScanResults(services.ScanResponse{Vulnerabilities: vulnerabilities}) diff --git a/utils/xsc/configprofile_test.go b/utils/xsc/configprofile_test.go index 86afca0a..7d8c8962 100644 --- a/utils/xsc/configprofile_test.go +++ b/utils/xsc/configprofile_test.go @@ -2,18 +2,19 @@ package xsc import ( "encoding/json" - "github.com/jfrog/jfrog-cli-security/utils" - "github.com/jfrog/jfrog-client-go/xsc/services" - "github.com/stretchr/testify/assert" "os" "testing" + + "github.com/jfrog/jfrog-cli-security/utils/validations" + "github.com/jfrog/jfrog-client-go/xsc/services" + "github.com/stretchr/testify/assert" ) func TestGetConfigProfile_ValidRequest_SuccessExpected(t *testing.T) { - mockServer, serverDetails := utils.XscServer(t, services.ConfigProfileMinXscVersion) + mockServer, serverDetails := validations.XscServer(t, services.ConfigProfileMinXscVersion) defer mockServer.Close() - configProfile, err := GetConfigProfile(serverDetails, utils.TestConfigProfileName) + configProfile, err := GetConfigProfile(serverDetails, validations.TestConfigProfileName) assert.NoError(t, err) profileFileContent, err := os.ReadFile("../../tests/testdata/other/configProfile/configProfileExample.json") @@ -27,10 +28,10 @@ func TestGetConfigProfile_ValidRequest_SuccessExpected(t *testing.T) { } func TestGetConfigProfile_TooLowXscVersion_FailureExpected(t *testing.T) { - mockServer, serverDetails := utils.XscServer(t, "1.0.0") + mockServer, serverDetails := validations.XscServer(t, "1.0.0") defer mockServer.Close() - configProfile, err := GetConfigProfile(serverDetails, utils.TestConfigProfileName) + configProfile, err := GetConfigProfile(serverDetails, validations.TestConfigProfileName) assert.Error(t, err) assert.Nil(t, configProfile) } From 944d192258fc52e72164b8d341edabaf76247abd Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 9 Sep 2024 14:08:49 +0300 Subject: [PATCH 50/82] fix tests --- utils/validations/test_validate_sarif.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index 57db57d4..ded3d6f5 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -40,8 +40,11 @@ func ValidateSarifIssuesCount(t *testing.T, params ValidationParams, results *sa var vulnerabilities, securityViolations, licenseViolations, applicableResults, undeterminedResults, notCoveredResults, notApplicableResults int iac := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, sarifparser.IacToolName)...) + vulnerabilities += iac secrets := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, sarifparser.SecretsToolName)...) + vulnerabilities += secrets sast := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, sarifparser.SastToolName)...) + vulnerabilities += sast scaRuns := sarifutils.GetRunsByToolName(results, sarifparser.ScaScannerToolName) for _, run := range scaRuns { From 38671ccf2381928779032b37a05fd50ee852d574 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 9 Sep 2024 14:52:33 +0300 Subject: [PATCH 51/82] fix merge --- utils/results/output/securityJobSummary.go | 2 +- utils/results/output/securityJobSummary_test.go | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/utils/results/output/securityJobSummary.go b/utils/results/output/securityJobSummary.go index e5b34f2f..e05e9d05 100644 --- a/utils/results/output/securityJobSummary.go +++ b/utils/results/output/securityJobSummary.go @@ -190,7 +190,7 @@ func RecordSarifOutput(cmdResults *results.SecurityCommandResults, includeVulner if err != nil || manager == nil { return } - if cmdResults.ExtendedScanResults == nil || !cmdResults.ExtendedScanResults.EntitledForJas { + if !cmdResults.EntitledForJas { // If no JAS no GHAS return } diff --git a/utils/results/output/securityJobSummary_test.go b/utils/results/output/securityJobSummary_test.go index d29857b9..fb591967 100644 --- a/utils/results/output/securityJobSummary_test.go +++ b/utils/results/output/securityJobSummary_test.go @@ -13,6 +13,7 @@ import ( "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/validations" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" clientTests "github.com/jfrog/jfrog-client-go/utils/tests" @@ -62,16 +63,14 @@ func TestSaveSarifOutputOnlyForJasEntitled(t *testing.T) { cleanUp := clientTests.SetEnvWithCallbackAndAssert(t, coreUtils.SummaryOutputDirPathEnv, tempDir) defer cleanUp() - assert.NoError(t, RecordSarifOutput(createDummyJasResult(testCase.isJasEntitled))) + assert.NoError(t, RecordSarifOutput(createDummyJasResult(testCase.isJasEntitled), true, true)) assert.Equal(t, testCase.isJasEntitled, hasFilesInDir(t, filepath.Join(tempDir, commandsummary.OutputDirName, "security", string(commandsummary.SarifReport)))) }) } } -func createDummyJasResult(entitled bool) *Results { - return &Results{ - ExtendedScanResults: &ExtendedScanResults{EntitledForJas: entitled}, - } +func createDummyJasResult(entitled bool) *results.SecurityCommandResults { + return &results.SecurityCommandResults{EntitledForJas: entitled} } func hasFilesInDir(t *testing.T, dir string) bool { From 272591c309a7985446777166f3bdd9895d82fbae Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 9 Sep 2024 15:09:53 +0300 Subject: [PATCH 52/82] fix static tests --- commands/enrich/enrich.go | 2 +- commands/scan/scan.go | 2 +- utils/formats/sarifutils/sarifutils.go | 4 ++-- utils/results/output/resultwriter.go | 2 +- utils/xsc/analyticsmetrics.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/commands/enrich/enrich.go b/commands/enrich/enrich.go index ca551e89..7fef30fb 100644 --- a/commands/enrich/enrich.go +++ b/commands/enrich/enrich.go @@ -196,7 +196,7 @@ func (enrichCmd *EnrichCommand) Run() (err error) { return err } if scanResults.GetErrors() != nil { - return errorutils.CheckErrorf(scanResults.GetErrors().Error()) + return errorutils.CheckError(scanResults.GetErrors()) } log.Info("Enrich process completed successfully.") return nil diff --git a/commands/scan/scan.go b/commands/scan/scan.go index 5c8b348e..44f978b2 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -327,7 +327,7 @@ func (scanCmd *ScanCommand) RunAndRecordResults(cmdType utils.CommandType, recor } } if cmdResults.GetErrors() != nil { - return errorutils.CheckErrorf(cmdResults.GetErrors().Error()) + return errorutils.CheckError(cmdResults.GetErrors()) } log.Info("Scan completed successfully.") return nil diff --git a/utils/formats/sarifutils/sarifutils.go b/utils/formats/sarifutils/sarifutils.go index 6e5e2c9f..ad1a5f2c 100644 --- a/utils/formats/sarifutils/sarifutils.go +++ b/utils/formats/sarifutils/sarifutils.go @@ -241,8 +241,8 @@ func GetResultProperty(key string, result *sarif.Result) string { return "" } if _, exists := result.Properties[key]; exists { - if _, ok := result.Properties[key].(string); ok { - return result.Properties[key].(string) + if value, ok := result.Properties[key].(string); ok { + return value } } return "" diff --git a/utils/results/output/resultwriter.go b/utils/results/output/resultwriter.go index 5d0122dc..27fa25a7 100644 --- a/utils/results/output/resultwriter.go +++ b/utils/results/output/resultwriter.go @@ -118,7 +118,7 @@ func shouldPrintTable(requestedScans []utils.SubScanType, subScan utils.SubScanT // PrintScanResults prints the scan results in the specified format. // Note that errors are printed only with SimpleJson format. func (rw *ResultsWriter) PrintScanResults() error { - if rw.commandResults.GetErrors() != nil { + if rw.commandResults.GetErrors() != nil && !rw.commandResults.HasInformation() { // Don't print if there are no results and only errors. return nil } diff --git a/utils/xsc/analyticsmetrics.go b/utils/xsc/analyticsmetrics.go index ed8fd13b..3fb4d795 100644 --- a/utils/xsc/analyticsmetrics.go +++ b/utils/xsc/analyticsmetrics.go @@ -168,7 +168,7 @@ func (ams *AnalyticsMetricsService) CreateXscAnalyticsGeneralEventFinalizeFromAu if err != nil { log.Warn(fmt.Sprintf("Failed to convert audit results to summary. %s", err.Error())) } - totalFindings := 0 + var totalFindings int if summary.HasViolations() { totalFindings = summary.GetTotalViolations() } else { From ae39323edcaf87ac4de71c3ce7ee2f13882ab51c Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 10 Sep 2024 09:20:52 +0300 Subject: [PATCH 53/82] CR changes --- commands/audit/audit.go | 4 +- commands/audit/sca/yarn/yarn_test.go | 21 ++-- commands/audit/scarunner.go | 5 +- commands/audit/scarunner_test.go | 2 +- commands/enrich/enrich.go | 4 +- commands/scan/scan.go | 27 +++--- tests/utils/test_utils.go | 8 +- utils/results/common.go | 95 ++++++------------- utils/results/conversion/convertor.go | 70 ++++---------- utils/results/conversion/convertor_test.go | 17 ++-- .../conversion/sarifparser/sarifparser.go | 42 +++----- .../simplejsonparser/simplejsonparser.go | 38 ++++---- .../simplejsonparser/simplejsonparser_test.go | 2 +- .../conversion/summaryparser/summaryparser.go | 28 +++--- .../conversion/tableparser/tableparser.go | 12 +-- utils/results/output/resultwriter.go | 9 +- utils/results/results.go | 47 ++++++--- utils/validations/test_validate_sarif.go | 43 +++++---- utils/validations/test_validate_sca.go | 7 +- .../validations/test_validate_simple_json.go | 31 +++--- utils/validations/test_validate_summary.go | 15 +-- utils/validations/test_validation.go | 23 ++++- 22 files changed, 249 insertions(+), 301 deletions(-) diff --git a/commands/audit/audit.go b/commands/audit/audit.go index 344cefae..f447c73e 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -136,7 +136,7 @@ func (auditCmd *AuditCommand) Run() (err error) { } var messages []string if !auditResults.EntitledForJas { - messages = []string{coreutils.PrintTitle("The ‘jf audit’ command also supports JFrog Advanced Security features, such as 'Contextual Analysis', 'Secret Detection', 'IaC Scan' and ‘SAST’.\nThis feature isn't enabled on your system. Read more - ") + coreutils.PrintLink("https://jfrog.com/xray/")} + messages = []string{coreutils.PrintTitle("The ‘jf audit’ command also supports JFrog Advanced Security features, such as 'Contextual Analysis', 'Secret Detection', 'IaC Scan' and ‘SAST’.\nThis feature isn't enabled on your system. Read more - ") + coreutils.PrintLink(utils.JasInfoURL)} } if err = output.NewResultsWriter(auditResults). SetHasViolationContext(auditCmd.HasViolationContext()). @@ -320,7 +320,7 @@ func detectScanTargets(cmdResults *results.SecurityCommandResults, params *Audit continue } if len(workingDirs) == 0 { - // Requested technology (from params) descriptors/indicators was not found, scan only requested directory for this technology. + // Requested technology (from params) descriptors/indicators were not found, scan only requested directory for this technology. cmdResults.NewScanResults(results.ScanTarget{Target: requestedDirectory, Technology: tech}) } for workingDir, descriptors := range workingDirs { diff --git a/commands/audit/sca/yarn/yarn_test.go b/commands/audit/sca/yarn/yarn_test.go index 06b1c385..2ada2a64 100644 --- a/commands/audit/sca/yarn/yarn_test.go +++ b/commands/audit/sca/yarn/yarn_test.go @@ -15,6 +15,7 @@ import ( ) func TestParseYarnDependenciesList(t *testing.T) { + npmId := techutils.Npm.GetPackageTypeId() yarnDependencies := map[string]*biutils.YarnDependency{ "pack1@npm:1.0.0": {Value: "pack1@npm:1.0.0", Details: biutils.YarnDepDetails{Version: "1.0.0", Dependencies: []biutils.YarnDependencyPointer{{Locator: "pack4@npm:4.0.0"}}}}, "pack2@npm:2.0.0": {Value: "pack2@npm:2.0.0", Details: biutils.YarnDepDetails{Version: "2.0.0", Dependencies: []biutils.YarnDependencyPointer{{Locator: "pack4@npm:4.0.0"}, {Locator: "pack5@npm:5.0.0"}}}}, @@ -23,31 +24,25 @@ func TestParseYarnDependenciesList(t *testing.T) { "pack5@npm:5.0.0": {Value: "pack5@npm:5.0.0", Details: biutils.YarnDepDetails{Version: "5.0.0", Dependencies: []biutils.YarnDependencyPointer{{Locator: "pack2@npm:2.0.0"}}}}, } - rootXrayId := techutils.Npm.GetPackageTypeId() + "@jfrog/pack3:3.0.0" + rootXrayId := npmId + "@jfrog/pack3:3.0.0" expectedTree := &xrayUtils.GraphNode{ Id: rootXrayId, Nodes: []*xrayUtils.GraphNode{ - {Id: techutils.Npm.GetPackageTypeId() + "pack1:1.0.0", + {Id: npmId + "pack1:1.0.0", Nodes: []*xrayUtils.GraphNode{ - {Id: techutils.Npm.GetPackageTypeId() + "pack4:4.0.0", + {Id: npmId + "pack4:4.0.0", Nodes: []*xrayUtils.GraphNode{}}, }}, - {Id: techutils.Npm.GetPackageTypeId() + "pack2:2.0.0", + {Id: npmId + "pack2:2.0.0", Nodes: []*xrayUtils.GraphNode{ - {Id: techutils.Npm.GetPackageTypeId() + "pack4:4.0.0", + {Id: npmId + "pack4:4.0.0", Nodes: []*xrayUtils.GraphNode{}}, - {Id: techutils.Npm.GetPackageTypeId() + "pack5:5.0.0", + {Id: npmId + "pack5:5.0.0", Nodes: []*xrayUtils.GraphNode{}}, }}, }, } - expectedUniqueDeps := []string{ - techutils.Npm.GetPackageTypeId() + "pack1:1.0.0", - techutils.Npm.GetPackageTypeId() + "pack2:2.0.0", - techutils.Npm.GetPackageTypeId() + "pack4:4.0.0", - techutils.Npm.GetPackageTypeId() + "pack5:5.0.0", - techutils.Npm.GetPackageTypeId() + "@jfrog/pack3:3.0.0", - } + expectedUniqueDeps := []string{npmId + "pack1:1.0.0", npmId + "pack2:2.0.0", npmId + "pack4:4.0.0", npmId + "pack5:5.0.0", npmId + "@jfrog/pack3:3.0.0"} xrayDependenciesTree, uniqueDeps := parseYarnDependenciesMap(yarnDependencies, rootXrayId) assert.ElementsMatch(t, uniqueDeps, expectedUniqueDeps, "First is actual, Second is Expected") diff --git a/commands/audit/scarunner.go b/commands/audit/scarunner.go index 33494eaf..80307ae0 100644 --- a/commands/audit/scarunner.go +++ b/commands/audit/scarunner.go @@ -37,7 +37,8 @@ import ( xrayCmdUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" ) -func shouldPreformScaScan(cmdResults *results.SecurityCommandResults) bool { +// We can only preform SCA scan if we identified at least one technology for a target. +func hasAtLeastOneTech(cmdResults *results.SecurityCommandResults) bool { if len(cmdResults.Targets) == 0 { return false } @@ -68,7 +69,7 @@ func buildDepTreeAndRunScaScan(auditParallelRunner *utils.SecurityParallelRunner if err != nil { return } - if !shouldPreformScaScan(cmdResults) { + if !hasAtLeastOneTech(cmdResults) { log.Info("Couldn't determine a package manager or build tool used by this project. Skipping the SCA scan...") return } diff --git a/commands/audit/scarunner_test.go b/commands/audit/scarunner_test.go index 09b2fc5f..7db9d5f8 100644 --- a/commands/audit/scarunner_test.go +++ b/commands/audit/scarunner_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestGetDirectDependenciesList(t *testing.T) { +func TestGetDirectDependenciesFromTree(t *testing.T) { tests := []struct { dependenciesTrees []*xrayUtils.GraphNode expectedResult []string diff --git a/commands/enrich/enrich.go b/commands/enrich/enrich.go index 7fef30fb..89516b87 100644 --- a/commands/enrich/enrich.go +++ b/commands/enrich/enrich.go @@ -178,11 +178,11 @@ func (enrichCmd *EnrichCommand) Run() (err error) { scanResults.Error = errors.Join(scanResults.Error, fileCollectingErr) } - isxml, err := isXML(scanResults.Targets) + isXml, err := isXML(scanResults.Targets) if err != nil { return } - if isxml { + if isXml { if err = AppendVulnsToXML(scanResults); err != nil { return } diff --git a/commands/scan/scan.go b/commands/scan/scan.go index 44f978b2..86548d7c 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -57,19 +57,20 @@ type ScanCommand struct { spec *spec.SpecFiles threads int // The location of the downloaded Xray indexer binary on the local file system. - indexerPath string - indexerTempDir string - outputFormat format.OutputFormat - projectKey string - minSeverityFilter severityutils.Severity - watches []string - includeVulnerabilities bool - includeLicenses bool - fail bool - printExtendedTable bool - bypassArchiveLimits bool - fixableOnly bool - progress ioUtils.ProgressMgr + indexerPath string + indexerTempDir string + outputFormat format.OutputFormat + projectKey string + minSeverityFilter severityutils.Severity + watches []string + includeVulnerabilities bool + includeLicenses bool + fail bool + printExtendedTable bool + bypassArchiveLimits bool + fixableOnly bool + progress ioUtils.ProgressMgr + // JAS is only supported for Docker images. commandSupportsJAS bool analyticsMetricsService *xsc.AnalyticsMetricsService } diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index 24aa5d14..9f4b2a47 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -140,7 +140,7 @@ func ChangeWD(t *testing.T, newPath string) string { func ReadCmdScanResults(t *testing.T, path string) *results.SecurityCommandResults { content, err := os.ReadFile(path) - assert.NoError(t, err) + require.NoError(t, err) var cmdResults *results.SecurityCommandResults if !assert.NoError(t, json.Unmarshal(content, &cmdResults)) { return &results.SecurityCommandResults{} @@ -182,7 +182,7 @@ func convertSarifRunPathsForOS(runs ...*sarif.Run) { func ReadSimpleJsonResults(t *testing.T, path string) formats.SimpleJsonResults { content, err := os.ReadFile(path) - assert.NoError(t, err) + require.NoError(t, err) var results formats.SimpleJsonResults if !assert.NoError(t, json.Unmarshal(content, &results)) { return formats.SimpleJsonResults{} @@ -265,7 +265,7 @@ func convertScaSimpleJsonPathsForOS(potentialComponents *[]formats.ComponentRow, func ReadSarifResults(t *testing.T, path string) *sarif.Report { content, err := os.ReadFile(path) - assert.NoError(t, err) + require.NoError(t, err) var results *sarif.Report if !assert.NoError(t, json.Unmarshal(content, &results)) { return &sarif.Report{} @@ -277,7 +277,7 @@ func ReadSarifResults(t *testing.T, path string) *sarif.Report { func ReadSummaryResults(t *testing.T, path string) formats.ResultsSummary { content, err := os.ReadFile(path) - assert.NoError(t, err) + require.NoError(t, err) var results formats.ResultsSummary if !assert.NoError(t, json.Unmarshal(content, &results)) { return formats.ResultsSummary{} diff --git a/utils/results/common.go b/utils/results/common.go index d5267a0e..2399e5d9 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -31,12 +31,12 @@ const ( ) var ( - ErrConvertorReset = fmt.Errorf("reset must be called before parsing new scan results metadata") - ErrConvertorNewScan = fmt.Errorf("ParseNewTargetResults must be called before starting to parse issues") + ErrResetConvertor = fmt.Errorf("reset must be called before parsing new scan results metadata") + ErrNoTargetConvertor = fmt.Errorf("ParseNewTargetResults must be called before starting to parse issues") ) func NewFailBuildError() error { - return coreutils.CliError{ExitCode: coreutils.ExitCodeVulnerableBuild, ErrorMsg: "One or more of the violations found are set to fail builds that include them"} + return coreutils.CliError{ExitCode: coreutils.ExitCodeVulnerableBuild, ErrorMsg: "One or more of the detected violations are configured to fail the build that including them"} } // In case one (or more) of the violations contains the field FailBuild set to true, CliError with exit code 3 will be returned. @@ -57,7 +57,7 @@ type ParseLicensesFunc func(license services.License, impactedPackagesName, impa type ParseJasFunc func(run *sarif.Run, rule *sarif.ReportingDescriptor, severity severityutils.Severity, result *sarif.Result, location *sarif.Location) error // PrepareJasIssues allows to iterate over the provided SARIF runs and call the provided handler for each issue to process it. -func PrepareJasIssues(target ScanTarget, runs []*sarif.Run, entitledForJas bool, handler ParseJasFunc) error { +func PrepareJasIssues(runs []*sarif.Run, entitledForJas bool, handler ParseJasFunc) error { if !entitledForJas || handler == nil { return nil } @@ -88,8 +88,8 @@ func PrepareJasIssues(target ScanTarget, runs []*sarif.Run, entitledForJas bool, return nil } -// PrepareScaVulnerabilities allows to iterate over the provided vulnerabilities and call the provided handler for each vulnerability to process it. -func PrepareScaVulnerabilities(target ScanTarget, vulnerabilities []services.Vulnerability, pretty, entitledForJas bool, applicabilityRuns []*sarif.Run, handler ParseScaVulnerabilityFunc) error { +// PrepareScaVulnerabilities allows to iterate over the provided SCA security vulnerabilities and call the provided handler for each impacted component/package with a vulnerability to process it. +func PrepareScaVulnerabilities(target ScanTarget, vulnerabilities []services.Vulnerability, entitledForJas bool, applicabilityRuns []*sarif.Run, handler ParseScaVulnerabilityFunc) error { if handler == nil { return nil } @@ -116,8 +116,8 @@ func PrepareScaVulnerabilities(target ScanTarget, vulnerabilities []services.Vul return nil } -// PrepareScaViolations allows to iterate over the provided violations and call the provided handler for each violation to process it. -func PrepareScaViolations(target ScanTarget, violations []services.Violation, pretty, entitledForJas bool, applicabilityRuns []*sarif.Run, securityHandler ParseScaViolationFunc, licenseHandler ParseScaViolationFunc, operationalRiskHandler ParseScaViolationFunc) (watches []string, failBuild bool, err error) { +// PrepareScaViolations allows to iterate over the provided SCA violations and call the provided handler for each impacted component/package with a violation to process it. +func PrepareScaViolations(target ScanTarget, violations []services.Violation, entitledForJas bool, applicabilityRuns []*sarif.Run, securityHandler ParseScaViolationFunc, licenseHandler ParseScaViolationFunc, operationalRiskHandler ParseScaViolationFunc) (watches []string, failBuild bool, err error) { if securityHandler == nil && licenseHandler == nil && operationalRiskHandler == nil { return } @@ -191,7 +191,7 @@ func PrepareScaViolations(target ScanTarget, violations []services.Violation, pr return } -// PrepareLicenses allows to iterate over the provided licenses and call the provided handler for each license to process it. +// PrepareLicenses allows to iterate over the provided licenses and call the provided handler for each component/package with a license to process it. func PrepareLicenses(target ScanTarget, licenses []services.License, handler ParseLicensesFunc) error { if handler == nil { return nil @@ -355,7 +355,7 @@ func GetViolatedLicenses(allowedLicenses []string, licenses []services.License) return } -// appendUniqueImpactPathsForMultipleRoots appends the source impact path to the target impact path while avoiding duplicates. +// AppendUniqueImpactPathsForMultipleRoots appends the source impact path to the target impact path while avoiding duplicates. // Specifically, it is designed for handling multiple root projects, such as Maven or Gradle, by comparing each pair of paths and identifying the path that is closest to the direct dependency. func AppendUniqueImpactPathsForMultipleRoots(target [][]services.ImpactPathNode, source [][]services.ImpactPathNode) [][]services.ImpactPathNode { for targetPathIndex, targetPath := range target { @@ -431,20 +431,6 @@ func getImpactPathKey(path []services.ImpactPathNode) string { return key } -func SplitScaScanResults(results *SecurityCommandResults) ([]services.Violation, []services.Vulnerability, []services.License) { - var violations []services.Violation - var vulnerabilities []services.Vulnerability - var licenses []services.License - for _, scanTarget := range results.Targets { - for _, scaScan := range scanTarget.ScaResults.XrayResults { - violations = append(violations, scaScan.Violations...) - vulnerabilities = append(vulnerabilities, scaScan.Vulnerabilities...) - licenses = append(licenses, scaScan.Licenses...) - } - } - return violations, vulnerabilities, licenses -} - func GetCveApplicabilityField(cveId string, applicabilityScanResults []*sarif.Run, components map[string]services.Component) *formats.Applicability { if len(applicabilityScanResults) == 0 { return nil @@ -467,22 +453,9 @@ func GetCveApplicabilityField(cveId string, applicabilityScanResults []*sarif.Ru resultFound = true // Add new evidences from locations for _, location := range result.Locations { - fileName := sarifutils.GetRelativeLocationFileName(location, applicabilityRun.Invocations) - // TODO: maybe, move this logic to the convertor - if shouldDisqualifyEvidence(components, fileName) { - continue + if evidence := getEvidence(components, result, location, applicabilityRun.Invocations...); evidence != nil { + applicability.Evidence = append(applicability.Evidence, *evidence) } - applicability.Evidence = append(applicability.Evidence, formats.Evidence{ - Location: formats.Location{ - File: fileName, - StartLine: sarifutils.GetLocationStartLine(location), - StartColumn: sarifutils.GetLocationStartColumn(location), - EndLine: sarifutils.GetLocationEndLine(location), - EndColumn: sarifutils.GetLocationEndColumn(location), - Snippet: sarifutils.GetLocationSnippet(location), - }, - Reason: sarifutils.GetResultMsgText(result), - }) } } switch { @@ -498,26 +471,22 @@ func GetCveApplicabilityField(cveId string, applicabilityScanResults []*sarif.Ru return &applicability } -func GetApplicableCvesStatus(entitledForJas bool, applicabilityScanResults []*sarif.Run, cves ...services.Cve) jasutils.ApplicabilityStatus { - if !entitledForJas || len(applicabilityScanResults) == 0 { - return jasutils.NotScanned - } - if len(cves) == 0 { - return jasutils.NotCovered +func getEvidence(components map[string]services.Component, result *sarif.Result, location *sarif.Location, invocations ...*sarif.Invocation) *formats.Evidence { + fileName := sarifutils.GetRelativeLocationFileName(location, invocations) + if shouldDisqualifyEvidence(components, fileName) { + return nil } - var applicableStatuses []jasutils.ApplicabilityStatus - for _, cve := range cves { - for _, applicabilityRun := range applicabilityScanResults { - if rule, _ := applicabilityRun.GetRuleById(jasutils.CveToApplicabilityRuleId(cve.Id)); rule != nil { - status := getApplicabilityStatusFromRule(rule) - if status != "" { - applicableStatuses = append(applicableStatuses, status) - } - } - } + return &formats.Evidence{ + Location: formats.Location{ + File: fileName, + StartLine: sarifutils.GetLocationStartLine(location), + StartColumn: sarifutils.GetLocationStartColumn(location), + EndLine: sarifutils.GetLocationEndLine(location), + EndColumn: sarifutils.GetLocationEndColumn(location), + Snippet: sarifutils.GetLocationSnippet(location), + }, + Reason: sarifutils.GetResultMsgText(result), } - return getFinalApplicabilityStatus(applicableStatuses) - } func GetApplicableCveStatus(entitledForJas bool, applicabilityScanResults []*sarif.Run, cves []formats.CveRow) jasutils.ApplicabilityStatus { @@ -586,7 +555,7 @@ func shouldDisqualifyEvidence(components map[string]services.Component, evidence if !strings.HasPrefix(key, techutils.Npm.GetPackageTypeId()) { return } - dependencyName := extractDependencyNameFromComponent(key, techutils.Npm.GetPackageTypeId()) + dependencyName, _, _ := techutils.SplitComponentId(key) // Check both Unix & Windows paths. if strings.Contains(evidenceFilePath, nodeModules+"/"+dependencyName) || strings.Contains(evidenceFilePath, filepath.Join(nodeModules, dependencyName)) { return true @@ -595,16 +564,6 @@ func shouldDisqualifyEvidence(components map[string]services.Component, evidence return } -func extractDependencyNameFromComponent(key string, techIdentifier string) (dependencyName string) { - packageAndVersion := strings.TrimPrefix(key, techIdentifier) - split := strings.Split(packageAndVersion, ":") - if len(split) < 2 { - return - } - dependencyName = split[0] - return -} - // If we don't get any statues it means the applicability scanner didn't run -> final value is not scanned // If at least one cve is applicable -> final value is applicable // Else if at least one cve is undetermined -> final value is undetermined diff --git a/utils/results/conversion/convertor.go b/utils/results/conversion/convertor.go index a16c8fc9..ab21bc28 100644 --- a/utils/results/conversion/convertor.go +++ b/utils/results/conversion/convertor.go @@ -29,10 +29,9 @@ type ResultConvertParams struct { IsMultipleRoots *bool // Create local license violations if repo context was not provided and a license is not in this list AllowedLicenses []string - // Output will contain only the unique violations determined by the GetUniqueKey function (SimpleJson only) SimplifiedOutput bool - // Convert the results to a pretty format if supported (Table and Sarif) + // Convert the results to a pretty format if supported (Table and SimpleJson only) Pretty bool } @@ -40,8 +39,8 @@ func NewCommandResultsConvertor(params ResultConvertParams) *CommandResultsConve return &CommandResultsConvertor{Params: params} } -// Parse a stream of results and convert to the desired format -type ResultsStreamFormatParser interface { +// Parse a stream of results and convert them to the desired format T +type ResultsStreamFormatParser[T interface{}] interface { // Reset the convertor to start converting a new command results Reset(cmdType utils.CommandType, multiScanId, xrayVersion string, entitledForJas, multipleTargets bool) error // Will be called for each scan target (indicating the current is done parsing and starting to parse a new scan) @@ -54,61 +53,35 @@ type ResultsStreamFormatParser interface { ParseSecrets(target results.ScanTarget, secrets ...*sarif.Run) error ParseIacs(target results.ScanTarget, iacs ...*sarif.Run) error ParseSast(target results.ScanTarget, sast ...*sarif.Run) error + // When done parsing the stream results, get the converted content + Get() (T, error) } func (c *CommandResultsConvertor) ConvertToSimpleJson(cmdResults *results.SecurityCommandResults) (simpleJsonResults formats.SimpleJsonResults, err error) { parser := simplejsonparser.NewCmdResultsSimpleJsonConverter(false, c.Params.SimplifiedOutput) - err = c.parseCommandResults(parser, cmdResults) - if err != nil { - return - } - content := parser.Get() - if content == nil { - simpleJsonResults = formats.SimpleJsonResults{} - } else { - simpleJsonResults = *content - } - return + return parseCommandResults(c.Params, parser, cmdResults) } func (c *CommandResultsConvertor) ConvertToSarif(cmdResults *results.SecurityCommandResults) (sarifReport *sarif.Report, err error) { - parser := sarifparser.NewCmdResultsSarifConverter(c.Params.Pretty, c.Params.IncludeVulnerabilities, c.Params.HasViolationContext) - err = c.parseCommandResults(parser, cmdResults) - if err != nil { - return - } - return parser.Get() + parser := sarifparser.NewCmdResultsSarifConverter(c.Params.IncludeVulnerabilities, c.Params.HasViolationContext) + return parseCommandResults(c.Params, parser, cmdResults) } func (c *CommandResultsConvertor) ConvertToTable(cmdResults *results.SecurityCommandResults) (tableResults formats.ResultsTables, err error) { parser := tableparser.NewCmdResultsTableConverter(c.Params.Pretty) - err = c.parseCommandResults(parser, cmdResults) - if err != nil { - return - } - content := parser.Get() - if content == nil { - tableResults = formats.ResultsTables{} - } else { - tableResults = *content - } - return + return parseCommandResults(c.Params, parser, cmdResults) } func (c *CommandResultsConvertor) ConvertToSummary(cmdResults *results.SecurityCommandResults) (summaryResults formats.ResultsSummary, err error) { parser := summaryparser.NewCmdResultsSummaryConverter(c.Params.IncludeVulnerabilities, c.Params.HasViolationContext) - err = c.parseCommandResults(parser, cmdResults) - if err != nil { - return - } - return *parser.Get(), nil + return parseCommandResults(c.Params, parser, cmdResults) } -func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormatParser, cmdResults *results.SecurityCommandResults) (err error) { +func parseCommandResults[T interface{}](params ResultConvertParams, parser ResultsStreamFormatParser[T], cmdResults *results.SecurityCommandResults) (converted T, err error) { jasEntitled := cmdResults.EntitledForJas multipleTargets := cmdResults.HasMultipleTargets() - if c.Params.IsMultipleRoots != nil { - multipleTargets = *c.Params.IsMultipleRoots + if params.IsMultipleRoots != nil { + multipleTargets = *params.IsMultipleRoots } if err = parser.Reset(cmdResults.CmdType, cmdResults.MultiScanId, cmdResults.XrayVersion, jasEntitled, multipleTargets); err != nil { return @@ -118,7 +91,7 @@ func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormat return } if targetScansResults.ScaResults != nil { - if err = c.parseScaResults(parser, targetScansResults, jasEntitled); err != nil { + if err = parseScaResults(params, parser, targetScansResults, jasEntitled); err != nil { return } } @@ -135,10 +108,10 @@ func (c *CommandResultsConvertor) parseCommandResults(parser ResultsStreamFormat return } } - return + return parser.Get() } -func (c *CommandResultsConvertor) parseScaResults(parser ResultsStreamFormatParser, targetScansResults *results.TargetResults, jasEntitled bool) (err error) { +func parseScaResults[T interface{}](params ResultConvertParams, parser ResultsStreamFormatParser[T], targetScansResults *results.TargetResults, jasEntitled bool) (err error) { if targetScansResults.ScaResults == nil { return } @@ -148,24 +121,24 @@ func (c *CommandResultsConvertor) parseScaResults(parser ResultsStreamFormatPars if jasEntitled && targetScansResults.JasResults != nil { applicableRuns = targetScansResults.JasResults.ApplicabilityScanResults } - if c.Params.IncludeVulnerabilities { + if params.IncludeVulnerabilities { if err = parser.ParseVulnerabilities(actualTarget, scaResults, applicableRuns...); err != nil { return } } - if c.Params.HasViolationContext { + if params.HasViolationContext { if err = parser.ParseViolations(actualTarget, scaResults, applicableRuns...); err != nil { return } - } else if len(scaResults.Violations) == 0 && len(c.Params.AllowedLicenses) > 0 { + } else if len(scaResults.Violations) == 0 && len(params.AllowedLicenses) > 0 { // If no violations were found, check if there are licenses that are not allowed - if scaResults.Violations = results.GetViolatedLicenses(c.Params.AllowedLicenses, scaResults.Licenses); len(scaResults.Violations) > 0 { + if scaResults.Violations = results.GetViolatedLicenses(params.AllowedLicenses, scaResults.Licenses); len(scaResults.Violations) > 0 { if err = parser.ParseViolations(actualTarget, scaResults); err != nil { return } } } - if c.Params.IncludeLicenses { + if params.IncludeLicenses { if err = parser.ParseLicenses(actualTarget, scaResults.Licenses); err != nil { return } @@ -178,7 +151,6 @@ func (c *CommandResultsConvertor) parseScaResults(parser ResultsStreamFormatPars func getScaScanTarget(scaResults *results.ScaScanResults, target string) string { if scaResults == nil || len(scaResults.Descriptors) == 0 { // If No Sca scan or no descriptors discovered, use the scan target (build-scan, binary-scan...) - // TODO: make sure works for build-scan since its not a file return target } // Get the one that it's directory is the prefix of the target and the shortest diff --git a/utils/results/conversion/convertor_test.go b/utils/results/conversion/convertor_test.go index 08ca7fbb..5e44af73 100644 --- a/utils/results/conversion/convertor_test.go +++ b/utils/results/conversion/convertor_test.go @@ -31,17 +31,14 @@ type conversionFormat string func getAuditValidationParams() validations.ValidationParams { return validations.ValidationParams{ - ExactResultsMatch: true, - + ExactResultsMatch: true, SecurityViolations: 11, - - Vulnerabilities: 19, - Applicable: 1, - NotApplicable: 7, - NotCovered: 4, - - Sast: 4, - Secrets: 3, + Vulnerabilities: 19, + Applicable: 1, + NotApplicable: 7, + NotCovered: 4, + Sast: 4, + Secrets: 3, } } diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index 08e04e89..779961c2 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -23,21 +23,12 @@ import ( ) const ( - FixedVersionSarifPropertyKey = "fixedVersion" - WatchSarifPropertyKey = "watch" - - SastToolName = "USAF" - IacToolName = "JFrog Terraform scanner" - // #nosec G101 -- Not credentials. - SecretsToolName = "JFrog Secrets scanner" - ContexualAnalysisToolName = "JFrog Applicability Scanner" - - // TODO: remove above if not used - CurrentWorkflowNameEnvVar = "GITHUB_WORKFLOW" CurrentWorkflowRunNumberEnvVar = "GITHUB_RUN_NUMBER" CurrentWorkflowWorkspaceEnvVar = "GITHUB_WORKSPACE" + FixedVersionSarifPropertyKey = "fixedVersion" + WatchSarifPropertyKey = "watch" jfrogFingerprintAlgorithmName = "jfrogFingerprintHash" MissingCveScore = "0" maxPossibleCve = 10.0 @@ -54,8 +45,6 @@ var ( ) type CmdResultsSarifConverter struct { - // Pretty print the output text for Github Issues support - pretty bool // Include vulnerabilities/violations in the output includeVulnerabilities bool hasViolationContext bool @@ -69,12 +58,11 @@ type CmdResultsSarifConverter struct { currentCmdType utils.CommandType } -func NewCmdResultsSarifConverter(pretty, includeVulnerabilities, hasViolationContext bool) *CmdResultsSarifConverter { - return &CmdResultsSarifConverter{pretty: pretty, includeVulnerabilities: includeVulnerabilities, hasViolationContext: hasViolationContext} +func NewCmdResultsSarifConverter(includeVulnerabilities, hasViolationContext bool) *CmdResultsSarifConverter { + return &CmdResultsSarifConverter{includeVulnerabilities: includeVulnerabilities, hasViolationContext: hasViolationContext} } func (sc *CmdResultsSarifConverter) Get() (*sarif.Report, error) { - // Return the current report if sc.current == nil { return sarifutils.NewReport() } @@ -101,7 +89,7 @@ func (sc *CmdResultsSarifConverter) Reset(cmdType utils.CommandType, _, xrayVers func (sc *CmdResultsSarifConverter) ParseNewTargetResults(target results.ScanTarget, errors ...error) (err error) { if sc.current == nil { - return results.ErrConvertorReset + return results.ErrResetConvertor } if sc.scaCurrentRun != nil { // Flush the current run @@ -128,10 +116,10 @@ func (sc *CmdResultsSarifConverter) createScaRun(target results.ScanTarget, erro // validateBeforeParse checks if the parser is initialized to parse results (checks if Reset and at least one ParseNewTargetResults was called before) func (sc *CmdResultsSarifConverter) validateBeforeParse() (err error) { if sc.current == nil { - return results.ErrConvertorReset + return results.ErrResetConvertor } if (sc.hasViolationContext || sc.includeVulnerabilities) && sc.scaCurrentRun == nil { - return results.ErrConvertorNewScan + return results.ErrNoTargetConvertor } return } @@ -141,7 +129,7 @@ func (sc *CmdResultsSarifConverter) ParseViolations(target results.ScanTarget, s return } // Parse violations - sarifResults, sarifRules, err := PrepareSarifScaViolations(sc.currentCmdType, target, sc.scaCurrentRun, scanResponse.Violations, sc.pretty, sc.entitledForJas, applicabilityRuns...) + sarifResults, sarifRules, err := PrepareSarifScaViolations(sc.currentCmdType, target, scanResponse.Violations, sc.entitledForJas, applicabilityRuns...) if err != nil || len(sarifRules) == 0 || len(sarifResults) == 0 { return } @@ -153,7 +141,7 @@ func (sc *CmdResultsSarifConverter) ParseVulnerabilities(target results.ScanTarg if err = sc.validateBeforeParse(); err != nil || sc.scaCurrentRun == nil { return } - sarifResults, sarifRules, err := PrepareSarifScaVulnerabilities(sc.currentCmdType, target, scanResponse.Vulnerabilities, sc.pretty, sc.entitledForJas, applicabilityRuns...) + sarifResults, sarifRules, err := PrepareSarifScaVulnerabilities(sc.currentCmdType, target, scanResponse.Vulnerabilities, sc.entitledForJas, applicabilityRuns...) if err != nil || len(sarifRules) == 0 || len(sarifResults) == 0 { return } @@ -171,7 +159,7 @@ func (sc *CmdResultsSarifConverter) ParseSecrets(target results.ScanTarget, secr return } if sc.current == nil { - return results.ErrConvertorReset + return results.ErrResetConvertor } sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.SecretsScan, target, secrets...)...) return @@ -182,7 +170,7 @@ func (sc *CmdResultsSarifConverter) ParseIacs(target results.ScanTarget, iacs .. return } if sc.current == nil { - return results.ErrConvertorReset + return results.ErrResetConvertor } sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.IacScan, target, iacs...)...) return @@ -193,7 +181,7 @@ func (sc *CmdResultsSarifConverter) ParseSast(target results.ScanTarget, sast .. return } if sc.current == nil { - return results.ErrConvertorReset + return results.ErrResetConvertor } sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.SastScan, target, sast...)...) return @@ -209,13 +197,12 @@ func (sc *CmdResultsSarifConverter) addScaResultsToCurrentRun(rules map[string]* } } -func PrepareSarifScaViolations(cmdType utils.CommandType, target results.ScanTarget, run *sarif.Run, violations []services.Violation, pretty, entitledForJas bool, applicabilityRuns ...*sarif.Run) ([]*sarif.Result, map[string]*sarif.ReportingDescriptor, error) { +func PrepareSarifScaViolations(cmdType utils.CommandType, target results.ScanTarget, violations []services.Violation, entitledForJas bool, applicabilityRuns ...*sarif.Run) ([]*sarif.Result, map[string]*sarif.ReportingDescriptor, error) { sarifResults := []*sarif.Result{} rules := map[string]*sarif.ReportingDescriptor{} _, _, err := results.PrepareScaViolations( target, violations, - pretty, entitledForJas, applicabilityRuns, addSarifScaSecurityViolation(cmdType, &sarifResults, &rules), @@ -226,13 +213,12 @@ func PrepareSarifScaViolations(cmdType utils.CommandType, target results.ScanTar return sarifResults, rules, err } -func PrepareSarifScaVulnerabilities(cmdType utils.CommandType, target results.ScanTarget, vulnerabilities []services.Vulnerability, pretty, entitledForJas bool, applicabilityRuns ...*sarif.Run) ([]*sarif.Result, map[string]*sarif.ReportingDescriptor, error) { +func PrepareSarifScaVulnerabilities(cmdType utils.CommandType, target results.ScanTarget, vulnerabilities []services.Vulnerability, entitledForJas bool, applicabilityRuns ...*sarif.Run) ([]*sarif.Result, map[string]*sarif.ReportingDescriptor, error) { sarifResults := []*sarif.Result{} rules := map[string]*sarif.ReportingDescriptor{} err := results.PrepareScaVulnerabilities( target, vulnerabilities, - pretty, entitledForJas, applicabilityRuns, addSarifScaVulnerability(cmdType, &sarifResults, &rules), diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go index a5f000b8..645e62ff 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go @@ -31,16 +31,16 @@ func NewCmdResultsSimpleJsonConverter(pretty, uniqueScaIssues bool) *CmdResultsS return &CmdResultsSimpleJsonConverter{pretty: pretty, uniqueScaIssues: uniqueScaIssues} } -func (sjc *CmdResultsSimpleJsonConverter) Get() *formats.SimpleJsonResults { +func (sjc *CmdResultsSimpleJsonConverter) Get() (formats.SimpleJsonResults, error) { if sjc.current == nil { - return nil + return formats.SimpleJsonResults{}, nil } if sjc.uniqueScaIssues { sjc.current.Vulnerabilities = removeScaDuplications(sjc.current.Vulnerabilities, sjc.multipleRoots) sjc.current.SecurityViolations = removeScaDuplications(sjc.current.SecurityViolations, sjc.multipleRoots) } sortResults(sjc.current) - return sjc.current + return *sjc.current, nil } func (sjc *CmdResultsSimpleJsonConverter) Reset(_ utils.CommandType, multiScanId, _ string, entitledForJas, multipleTargets bool) (err error) { @@ -52,7 +52,7 @@ func (sjc *CmdResultsSimpleJsonConverter) Reset(_ utils.CommandType, multiScanId func (sjc *CmdResultsSimpleJsonConverter) ParseNewTargetResults(target results.ScanTarget, errors ...error) (err error) { if sjc.current == nil { - return results.ErrConvertorReset + return results.ErrResetConvertor } for _, err := range errors { if err != nil { @@ -64,7 +64,7 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseNewTargetResults(target results.S func (sjc *CmdResultsSimpleJsonConverter) ParseViolations(target results.ScanTarget, scaResponse services.ScanResponse, applicabilityRuns ...*sarif.Run) (err error) { if sjc.current == nil { - return results.ErrConvertorReset + return results.ErrResetConvertor } secViolationsSimpleJson, licViolationsSimpleJson, opRiskViolationsSimpleJson, err := PrepareSimpleJsonViolations(target, scaResponse, sjc.pretty, sjc.entitledForJas, applicabilityRuns...) if err != nil { @@ -78,7 +78,7 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseViolations(target results.ScanTar func (sjc *CmdResultsSimpleJsonConverter) ParseVulnerabilities(target results.ScanTarget, scaResponse services.ScanResponse, applicabilityRuns ...*sarif.Run) (err error) { if sjc.current == nil { - return results.ErrConvertorReset + return results.ErrResetConvertor } vulSimpleJson, err := PrepareSimpleJsonVulnerabilities(target, scaResponse, sjc.pretty, sjc.entitledForJas, applicabilityRuns...) if err != nil || len(vulSimpleJson) == 0 { @@ -90,7 +90,7 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseVulnerabilities(target results.Sc func (sjc *CmdResultsSimpleJsonConverter) ParseLicenses(target results.ScanTarget, licenses []services.License) (err error) { if sjc.current == nil { - return results.ErrConvertorReset + return results.ErrResetConvertor } licSimpleJson, err := PrepareSimpleJsonLicenses(target, licenses) if err != nil || len(licSimpleJson) == 0 { @@ -100,14 +100,14 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseLicenses(target results.ScanTarge return } -func (sjc *CmdResultsSimpleJsonConverter) ParseSecrets(target results.ScanTarget, secrets ...*sarif.Run) (err error) { +func (sjc *CmdResultsSimpleJsonConverter) ParseSecrets(_ results.ScanTarget, secrets ...*sarif.Run) (err error) { if !sjc.entitledForJas { return } if sjc.current == nil { - return results.ErrConvertorReset + return results.ErrResetConvertor } - secretsSimpleJson, err := PrepareSimpleJsonJasIssues(target, sjc.entitledForJas, sjc.pretty, secrets...) + secretsSimpleJson, err := PrepareSimpleJsonJasIssues(sjc.entitledForJas, sjc.pretty, secrets...) if err != nil || len(secretsSimpleJson) == 0 { return } @@ -115,14 +115,14 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseSecrets(target results.ScanTarget return } -func (sjc *CmdResultsSimpleJsonConverter) ParseIacs(target results.ScanTarget, iacs ...*sarif.Run) (err error) { +func (sjc *CmdResultsSimpleJsonConverter) ParseIacs(_ results.ScanTarget, iacs ...*sarif.Run) (err error) { if !sjc.entitledForJas { return } if sjc.current == nil { - return results.ErrConvertorReset + return results.ErrResetConvertor } - iacSimpleJson, err := PrepareSimpleJsonJasIssues(target, sjc.entitledForJas, sjc.pretty, iacs...) + iacSimpleJson, err := PrepareSimpleJsonJasIssues(sjc.entitledForJas, sjc.pretty, iacs...) if err != nil || len(iacSimpleJson) == 0 { return } @@ -130,14 +130,14 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseIacs(target results.ScanTarget, i return } -func (sjc *CmdResultsSimpleJsonConverter) ParseSast(target results.ScanTarget, sast ...*sarif.Run) (err error) { +func (sjc *CmdResultsSimpleJsonConverter) ParseSast(_ results.ScanTarget, sast ...*sarif.Run) (err error) { if !sjc.entitledForJas { return } if sjc.current == nil { - return results.ErrConvertorReset + return results.ErrResetConvertor } - sastSimpleJson, err := PrepareSimpleJsonJasIssues(target, sjc.entitledForJas, sjc.pretty, sast...) + sastSimpleJson, err := PrepareSimpleJsonJasIssues(sjc.entitledForJas, sjc.pretty, sast...) if err != nil || len(sastSimpleJson) == 0 { return } @@ -152,7 +152,6 @@ func PrepareSimpleJsonViolations(target results.ScanTarget, scaResponse services _, _, err := results.PrepareScaViolations( target, scaResponse.Violations, - pretty, jasEntitled, applicabilityRuns, addSimpleJsonSecurityViolation(&securityViolationsRows, pretty), @@ -167,7 +166,6 @@ func PrepareSimpleJsonVulnerabilities(target results.ScanTarget, scaResponse ser err := results.PrepareScaVulnerabilities( target, scaResponse.Vulnerabilities, - pretty, entitledForJas, applicabilityRuns, addSimpleJsonVulnerability(&vulnerabilitiesRows, pretty), @@ -296,9 +294,9 @@ func addSimpleJsonLicense(licenseViolationsRows *[]formats.LicenseRow) results.P } } -func PrepareSimpleJsonJasIssues(target results.ScanTarget, entitledForJas, pretty bool, jasIssues ...*sarif.Run) ([]formats.SourceCodeRow, error) { +func PrepareSimpleJsonJasIssues(entitledForJas, pretty bool, jasIssues ...*sarif.Run) ([]formats.SourceCodeRow, error) { var rows []formats.SourceCodeRow - err := results.PrepareJasIssues(target, jasIssues, entitledForJas, func(run *sarif.Run, rule *sarif.ReportingDescriptor, severity severityutils.Severity, result *sarif.Result, location *sarif.Location) error { + err := results.PrepareJasIssues(jasIssues, entitledForJas, func(run *sarif.Run, rule *sarif.ReportingDescriptor, severity severityutils.Severity, result *sarif.Result, location *sarif.Location) error { scannerDescription := "" if rule != nil { scannerDescription = sarifutils.GetRuleFullDescription(rule) diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go index 484d6c93..e3394056 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go @@ -693,7 +693,7 @@ func TestPrepareSimpleJsonJasIssues(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - out, err := PrepareSimpleJsonJasIssues(tc.target, tc.entitledForJas, false, tc.jasIssues...) + out, err := PrepareSimpleJsonJasIssues(tc.entitledForJas, false, tc.jasIssues...) assert.NoError(t, err) assert.ElementsMatch(t, tc.expectedOutput, out) }) diff --git a/utils/results/conversion/summaryparser/summaryparser.go b/utils/results/conversion/summaryparser/summaryparser.go index 331165b2..e07c99ba 100644 --- a/utils/results/conversion/summaryparser/summaryparser.go +++ b/utils/results/conversion/summaryparser/summaryparser.go @@ -24,15 +24,15 @@ func NewCmdResultsSummaryConverter(includeVulnerabilities, hasViolationContext b return &CmdResultsSummaryConverter{includeVulnerabilities: includeVulnerabilities, includeViolations: hasViolationContext} } -func (sc *CmdResultsSummaryConverter) Get() *formats.ResultsSummary { +func (sc *CmdResultsSummaryConverter) Get() (formats.ResultsSummary, error) { if sc.current == nil { - return &formats.ResultsSummary{} + return formats.ResultsSummary{}, nil } // Flush the last scan if err := sc.ParseNewTargetResults(results.ScanTarget{}, nil); err != nil { - return &formats.ResultsSummary{} + return formats.ResultsSummary{}, err } - return sc.current + return *sc.current, nil } func (sc *CmdResultsSummaryConverter) Reset(_ utils.CommandType, _, _ string, entitledForJas, _ bool) (err error) { @@ -43,7 +43,7 @@ func (sc *CmdResultsSummaryConverter) Reset(_ utils.CommandType, _, _ string, en func (sc *CmdResultsSummaryConverter) ParseNewTargetResults(target results.ScanTarget, _ ...error) (err error) { if sc.current == nil { - return results.ErrConvertorReset + return results.ErrResetConvertor } if sc.currentScan != nil { sc.current.Scans = append(sc.current.Scans, *sc.currentScan) @@ -61,10 +61,10 @@ func (sc *CmdResultsSummaryConverter) ParseNewTargetResults(target results.ScanT // validateBeforeParse checks if the parser is initialized to parse results (checks if Reset and at least one ParseNewTargetResults was called before) func (sc *CmdResultsSummaryConverter) validateBeforeParse() (err error) { if sc.current == nil { - return results.ErrConvertorReset + return results.ErrResetConvertor } if sc.currentScan == nil { - return results.ErrConvertorNewScan + return results.ErrNoTargetConvertor } return } @@ -88,7 +88,6 @@ func (sc *CmdResultsSummaryConverter) ParseViolations(target results.ScanTarget, watches, failBuild, err := results.PrepareScaViolations( target, scaResponse.Violations, - false, sc.entitledForJas, applicabilityRuns, sc.getScaSecurityViolationHandler(parsed), @@ -176,7 +175,6 @@ func (sc *CmdResultsSummaryConverter) ParseVulnerabilities(target results.ScanTa err = results.PrepareScaVulnerabilities( target, scaResponse.Vulnerabilities, - false, sc.entitledForJas, applicabilityRuns, sc.getScaVulnerabilityHandler(parsed), @@ -228,7 +226,7 @@ func (sc *CmdResultsSummaryConverter) ParseLicenses(target results.ScanTarget, l return } -func (sc *CmdResultsSummaryConverter) ParseSecrets(target results.ScanTarget, secrets ...*sarif.Run) (err error) { +func (sc *CmdResultsSummaryConverter) ParseSecrets(_ results.ScanTarget, secrets ...*sarif.Run) (err error) { if !sc.entitledForJas || sc.currentScan.Vulnerabilities == nil { // JAS results are only supported as vulnerabilities for now return @@ -239,10 +237,10 @@ func (sc *CmdResultsSummaryConverter) ParseSecrets(target results.ScanTarget, se if sc.currentScan.Vulnerabilities.SecretsResults == nil { sc.currentScan.Vulnerabilities.SecretsResults = &formats.ResultSummary{} } - return results.PrepareJasIssues(target, secrets, sc.entitledForJas, sc.getJasHandler(jasutils.Secrets)) + return results.PrepareJasIssues(secrets, sc.entitledForJas, sc.getJasHandler(jasutils.Secrets)) } -func (sc *CmdResultsSummaryConverter) ParseIacs(target results.ScanTarget, iacs ...*sarif.Run) (err error) { +func (sc *CmdResultsSummaryConverter) ParseIacs(_ results.ScanTarget, iacs ...*sarif.Run) (err error) { if !sc.entitledForJas || sc.currentScan.Vulnerabilities == nil { // JAS results are only supported as vulnerabilities for now return @@ -253,10 +251,10 @@ func (sc *CmdResultsSummaryConverter) ParseIacs(target results.ScanTarget, iacs if sc.currentScan.Vulnerabilities.IacResults == nil { sc.currentScan.Vulnerabilities.IacResults = &formats.ResultSummary{} } - return results.PrepareJasIssues(target, iacs, sc.entitledForJas, sc.getJasHandler(jasutils.IaC)) + return results.PrepareJasIssues(iacs, sc.entitledForJas, sc.getJasHandler(jasutils.IaC)) } -func (sc *CmdResultsSummaryConverter) ParseSast(target results.ScanTarget, sast ...*sarif.Run) (err error) { +func (sc *CmdResultsSummaryConverter) ParseSast(_ results.ScanTarget, sast ...*sarif.Run) (err error) { if !sc.entitledForJas || sc.currentScan.Vulnerabilities == nil { // JAS results are only supported as vulnerabilities for now return @@ -267,7 +265,7 @@ func (sc *CmdResultsSummaryConverter) ParseSast(target results.ScanTarget, sast if sc.currentScan.Vulnerabilities.SastResults == nil { sc.currentScan.Vulnerabilities.SastResults = &formats.ResultSummary{} } - return results.PrepareJasIssues(target, sast, sc.entitledForJas, sc.getJasHandler(jasutils.Sast)) + return results.PrepareJasIssues(sast, sc.entitledForJas, sc.getJasHandler(jasutils.Sast)) } func (sc *CmdResultsSummaryConverter) getJasHandler(scanType jasutils.JasScanType) results.ParseJasFunc { diff --git a/utils/results/conversion/tableparser/tableparser.go b/utils/results/conversion/tableparser/tableparser.go index f8cc4508..95e5777e 100644 --- a/utils/results/conversion/tableparser/tableparser.go +++ b/utils/results/conversion/tableparser/tableparser.go @@ -21,19 +21,19 @@ func NewCmdResultsTableConverter(pretty bool) *CmdResultsTableConverter { return &CmdResultsTableConverter{pretty: pretty, simpleJsonConvertor: simplejsonparser.NewCmdResultsSimpleJsonConverter(pretty, true)} } -func (tc *CmdResultsTableConverter) Get() *formats.ResultsTables { - simpleJsonFormat := tc.simpleJsonConvertor.Get() - if simpleJsonFormat == nil { - return &formats.ResultsTables{} +func (tc *CmdResultsTableConverter) Get() (formats.ResultsTables, error) { + simpleJsonFormat, err := tc.simpleJsonConvertor.Get() + if err != nil { + return formats.ResultsTables{}, err } - return &formats.ResultsTables{ + return formats.ResultsTables{ SecurityVulnerabilitiesTable: formats.ConvertToVulnerabilityTableRow(simpleJsonFormat.Vulnerabilities), LicenseViolationsTable: formats.ConvertToLicenseViolationTableRow(simpleJsonFormat.LicensesViolations), OperationalRiskViolationsTable: formats.ConvertToOperationalRiskViolationTableRow(simpleJsonFormat.OperationalRiskViolations), SecretsTable: formats.ConvertToSecretsTableRow(simpleJsonFormat.Secrets), IacTable: formats.ConvertToIacOrSastTableRow(simpleJsonFormat.Iacs), SastTable: formats.ConvertToIacOrSastTableRow(simpleJsonFormat.Sast), - } + }, nil } func (tc *CmdResultsTableConverter) Reset(cmdType utils.CommandType, multiScanId, xrayVersion string, entitledForJas, multipleTargets bool) (err error) { diff --git a/utils/results/output/resultwriter.go b/utils/results/output/resultwriter.go index 27fa25a7..e887310b 100644 --- a/utils/results/output/resultwriter.go +++ b/utils/results/output/resultwriter.go @@ -213,8 +213,6 @@ func (rw *ResultsWriter) printTables() (err error) { if err = rw.printOrSaveRawResults(true); err != nil { return } - log.Output() - if shouldPrintTable(rw.subScansPreformed, utils.ScaScan, rw.scanType) { if rw.hasViolationContext { if err = PrintViolationsTable(tableContent, rw.scanType, rw.printExtended); err != nil { @@ -252,6 +250,8 @@ func (rw *ResultsWriter) printTables() (err error) { // Set printExtended to true to print fields with 'extended' tag. // If the scan argument is set to true, print the scan tables. func PrintVulnerabilitiesTable(tables formats.ResultsTables, scanType services.ScanType, techDetected, printExtended bool) error { + // Space before the tables + log.Output() if scanType == services.Binary { return coreutils.PrintTable(formats.ConvertSecurityTableRowToScanTableRow(tables.SecurityVulnerabilitiesTable), "Vulnerable Components", @@ -270,6 +270,8 @@ func PrintVulnerabilitiesTable(tables formats.ResultsTables, scanType services.S // Set printExtended to true to print fields with 'extended' tag. // If the scan argument is set to true, print the scan tables. func PrintViolationsTable(tables formats.ResultsTables, scanType services.ScanType, printExtended bool) (err error) { + // Space before the tables + log.Output() if scanType == services.Binary { err = coreutils.PrintTable(formats.ConvertSecurityTableRowToScanTableRow(tables.SecurityVulnerabilitiesTable), "Security Violations", "No security violations were found", printExtended) if err != nil { @@ -304,6 +306,8 @@ func PrintViolationsTable(tables formats.ResultsTables, scanType services.ScanTy // Set printExtended to true to print fields with 'extended' tag. // If the scan argument is set to true, print the scan tables. func PrintLicensesTable(tables formats.ResultsTables, printExtended bool, scanType services.ScanType) error { + // Space before the tables + log.Output() if scanType == services.Binary { return coreutils.PrintTable(formats.ConvertLicenseTableRowToScanTableRow(tables.LicensesTable), "Licenses", "No licenses were found", printExtended) } @@ -314,6 +318,7 @@ func PrintJasTable(tables formats.ResultsTables, entitledForJas bool, scanType j if !entitledForJas { return nil } + // Space before the tables log.Output() switch scanType { case jasutils.Secrets: diff --git a/utils/results/results.go b/utils/results/results.go index dd5793e0..a1ee4b3a 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -2,6 +2,7 @@ package results import ( "errors" + "fmt" "strings" "sync" @@ -28,15 +29,6 @@ type SecurityCommandResults struct { Error error `json:"error,omitempty"` } -type ScanTarget struct { - // Physical location of the target: Working directory (audit) / binary to scan (scan / docker scan) - Target string `json:"target,omitempty"` - // Logical name of the target (build name / module name / docker image name...) - Name string `json:"name,omitempty"` - // Optional field (not used only in build scan) to provide the technology of the target - Technology techutils.Technology `json:"technology,omitempty"` -} - type TargetResults struct { ScanTarget // All scan results for the target @@ -62,6 +54,30 @@ type JasScansResults struct { SastScanResults []*sarif.Run `json:"sast,omitempty"` } +type ScanTarget struct { + // Physical location of the target: Working directory (audit) / binary to scan (scan / docker scan) + Target string `json:"target,omitempty"` + // Logical name of the target (build name / module name / docker image name...) + Name string `json:"name,omitempty"` + // Optional field (not used only in build scan) to provide the technology of the target + Technology techutils.Technology `json:"technology,omitempty"` +} + +func (st ScanTarget) Copy(newTarget string) ScanTarget { + return ScanTarget{Target: newTarget, Name: st.Name, Technology: st.Technology} +} + +func (st ScanTarget) String() (str string) { + str = st.Target + if st.Name != "" { + str = st.Name + } + if st.Technology != "" { + str += fmt.Sprintf(" [%s]", st.Technology) + } + return +} + func NewCommandResults(cmdType utils.CommandType, xrayVersion string, entitledForJas bool) *SecurityCommandResults { return &SecurityCommandResults{CmdType: cmdType, XrayVersion: xrayVersion, EntitledForJas: entitledForJas, targetsMutex: sync.Mutex{}} } @@ -100,9 +116,7 @@ func (r *SecurityCommandResults) GetJasScansResults(scanType jasutils.JasScanTyp func (r *SecurityCommandResults) GetErrors() (err error) { err = r.Error for _, target := range r.Targets { - for _, targetErr := range target.Errors { - err = errors.Join(err, targetErr) - } + err = errors.Join(err, fmt.Errorf("target '%s' errors:\n%s", target.String(), target.GetErrors())) } return } @@ -123,7 +137,7 @@ func (r *SecurityCommandResults) HasMultipleTargets() bool { } for _, scanTarget := range r.Targets { // If there is more than one SCA scan target (i.e multiple files with dependencies information) - if scanTarget.ScaResults != nil && (len(scanTarget.ScaResults.XrayResults) > 0 || (scanTarget.ScaResults.IsMultipleRootProject != nil && *scanTarget.ScaResults.IsMultipleRootProject)) { + if scanTarget.ScaResults != nil && (len(scanTarget.ScaResults.XrayResults) > 1 || (scanTarget.ScaResults.IsMultipleRootProject != nil && *scanTarget.ScaResults.IsMultipleRootProject)) { return true } } @@ -162,8 +176,11 @@ func (r *SecurityCommandResults) NewScanResults(target ScanTarget) *TargetResult return targetResults } -func (st ScanTarget) Copy(newTarget string) ScanTarget { - return ScanTarget{Target: newTarget, Name: st.Name, Technology: st.Technology} +func (sr *TargetResults) GetErrors() (err error) { + for _, targetErr := range sr.Errors { + err = errors.Join(err, targetErr) + } + return } func (sr *TargetResults) GetWatches() []string { diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index ded3d6f5..a5ea3fb3 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -1,7 +1,6 @@ package validations import ( - "encoding/json" "fmt" "strings" "testing" @@ -13,16 +12,16 @@ import ( "github.com/stretchr/testify/assert" ) -// Content should be a Json string of sarif.Report and will be unmarshal. -// Value is set as the Actual content in the validation params -func VerifySarifResults(t *testing.T, content string, params ValidationParams) { - var results sarif.Report - err := json.Unmarshal([]byte(content), &results) - assert.NoError(t, err) - params.Actual = results - ValidateCommandSarifOutput(t, params) -} +const ( + SastToolName = "USAF" + IacToolName = "JFrog Terraform scanner" + SecretsToolName = "JFrog Secrets scanner" +) +// Validate sarif report according to the expected values and issue counts in the validation params. +// Value/Actual content should be a *sarif.Report in the validation params +// If ExactResultsMatch is true, the validation will check exact values and not only the 'equal or grater' counts / existence of expected attributes. +// For Integration tests with JFrog API, ExactResultsMatch should be set to false. func ValidateCommandSarifOutput(t *testing.T, params ValidationParams) { results, ok := params.Actual.(*sarif.Report) if assert.True(t, ok, "Actual content is not a *sarif.Report") { @@ -30,20 +29,24 @@ func ValidateCommandSarifOutput(t *testing.T, params ValidationParams) { if params.Expected != nil { expectedResults, ok := params.Expected.(*sarif.Report) if assert.True(t, ok, "Expected content is not a *sarif.Report") { - ValidateSarifResults(t, params.ExactResultsMatch, expectedResults, results) + ValidateSarifReport(t, params.ExactResultsMatch, expectedResults, results) } } } } +// Validate sarif report according to the expected counts in the validation params. +// Actual content should be a *sarif.Report in the validation params. +// If Expected is provided, the validation will check if the Actual content matches the expected results. +// If ExactResultsMatch is true, the validation will check exact values and not only the 'equal or grater' counts / existence of expected attributes. (For Integration tests with JFrog API, ExactResultsMatch should be set to false) func ValidateSarifIssuesCount(t *testing.T, params ValidationParams, results *sarif.Report) { var vulnerabilities, securityViolations, licenseViolations, applicableResults, undeterminedResults, notCoveredResults, notApplicableResults int - iac := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, sarifparser.IacToolName)...) + iac := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, IacToolName)...) vulnerabilities += iac - secrets := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, sarifparser.SecretsToolName)...) + secrets := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, SecretsToolName)...) vulnerabilities += secrets - sast := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, sarifparser.SastToolName)...) + sast := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, SastToolName)...) vulnerabilities += sast scaRuns := sarifutils.GetRunsByToolName(results, sarifparser.ScaScannerToolName) @@ -113,8 +116,8 @@ func isSecurityIssue(result *sarif.Result) bool { return false } -func ValidateSarifResults(t *testing.T, exactMatch bool, expected, actual *sarif.Report) { - validateContent(t, exactMatch, StringValidation{Expected: expected.Version, Actual: actual.Version, Msg: "Sarif version mismatch"}) +func ValidateSarifReport(t *testing.T, exactMatch bool, expected, actual *sarif.Report) { + ValidateContent(t, exactMatch, StringValidation{Expected: expected.Version, Actual: actual.Version, Msg: "Sarif version mismatch"}) for _, run := range expected.Runs { // expect Invocation if !assert.Len(t, run.Invocations, 1, "Expected exactly one invocation for run with tool name %s", run.Tool.Driver.Name) { @@ -139,7 +142,7 @@ func getRunByInvocationTargetAndToolName(target, toolName string, content []*sar } func validateSarifRun(t *testing.T, exactMatch bool, expected, actual *sarif.Run) { - validateContent(t, exactMatch, + ValidateContent(t, exactMatch, PointerValidation[string]{Expected: expected.Tool.Driver.InformationURI, Actual: actual.Tool.Driver.InformationURI, Msg: fmt.Sprintf("Run tool information URI mismatch for tool %s", expected.Tool.Driver.Name)}, PointerValidation[string]{Expected: expected.Tool.Driver.Version, Actual: actual.Tool.Driver.Version, Msg: fmt.Sprintf("Run tool version mismatch for tool %s", expected.Tool.Driver.Name)}, ) @@ -163,7 +166,7 @@ func validateSarifRun(t *testing.T, exactMatch bool, expected, actual *sarif.Run } func validateSarifRule(t *testing.T, exactMatch bool, toolName string, expected, actual *sarif.ReportingDescriptor) { - validateContent(t, exactMatch, + ValidateContent(t, exactMatch, StringValidation{Expected: sarifutils.GetRuleFullDescription(expected), Actual: sarifutils.GetRuleFullDescription(actual), Msg: fmt.Sprintf("Run tool %s: Rule full description mismatch for rule %s", toolName, expected.ID)}, StringValidation{Expected: sarifutils.GetRuleFullDescriptionMarkdown(expected), Actual: sarifutils.GetRuleFullDescriptionMarkdown(actual), Msg: fmt.Sprintf("Run tool %s: Rule full description markdown mismatch for rule %s", toolName, expected.ID)}, StringValidation{Expected: sarifutils.GetRuleShortDescription(expected), Actual: sarifutils.GetRuleShortDescription(actual), Msg: fmt.Sprintf("Run tool %s: Rule short description mismatch for rule %s", toolName, expected.ID)}, @@ -201,7 +204,7 @@ func hasSameLocations(expected, actual *sarif.Result) bool { } func validateSarifResult(t *testing.T, exactMatch bool, toolName string, expected, actual *sarif.Result) { - validateContent(t, exactMatch, + ValidateContent(t, exactMatch, StringValidation{Expected: sarifutils.GetResultLevel(expected), Actual: sarifutils.GetResultLevel(actual), Msg: fmt.Sprintf("Run tool %s: Result level mismatch for rule %s", toolName, sarifutils.GetResultRuleId(expected))}, ) // validate properties @@ -234,7 +237,7 @@ func validateSarifProperties(t *testing.T, exactMatch bool, expected, actual map if expectedStr, ok := expectedValue.(string); ok { actualStr, ok := actualValue.(string) if assert.True(t, ok, fmt.Sprintf("Run tool %s: Expected property with key %s is not a string for rule %s", toolName, key, ruleID)) { - validateContent(t, exactMatch, StringValidation{Expected: expectedStr, Actual: actualStr, Msg: fmt.Sprintf("Run tool %s: Rule property mismatch for rule %s", toolName, ruleID)}) + ValidateContent(t, exactMatch, StringValidation{Expected: expectedStr, Actual: actualStr, Msg: fmt.Sprintf("Run tool %s: Rule property mismatch for rule %s", toolName, ruleID)}) continue } assert.Fail(t, fmt.Sprintf("Run tool %s: Expected property with key %s is a string for rule %s", toolName, key, ruleID)) diff --git a/utils/validations/test_validate_sca.go b/utils/validations/test_validate_sca.go index 53289bd7..18b04bff 100644 --- a/utils/validations/test_validate_sca.go +++ b/utils/validations/test_validate_sca.go @@ -10,9 +10,10 @@ import ( "github.com/stretchr/testify/assert" ) -// Validation on SCA content only (No JAS in this content), with the option to provide expected results. -// Content should be a Json string of slice of []services.ScanResponse and will be unmarshal. -// Value is set as the Actual content in the validation params +// Validate SCA content only (No JAS in this content) according to the expected values and issue counts in the validation params. +// Content/Expected should be a []services.ScanResponse in the validation params. +// If Expected is provided, the validation will check if the Actual content matches the expected results. +// If ExactResultsMatch is true, the validation will check exact values and not only the 'equal or grater' counts / existence of expected attributes. (For Integration tests with JFrog API, ExactResultsMatch should be set to false) func VerifyJsonResults(t *testing.T, content string, params ValidationParams) { var results []services.ScanResponse err := json.Unmarshal([]byte(content), &results) diff --git a/utils/validations/test_validate_simple_json.go b/utils/validations/test_validate_simple_json.go index 3902e176..4507cf3a 100644 --- a/utils/validations/test_validate_simple_json.go +++ b/utils/validations/test_validate_simple_json.go @@ -10,8 +10,10 @@ import ( "github.com/stretchr/testify/assert" ) -// Content should be a Json string of slice of formats.SimpleJsonResults and will be unmarshal. -// Value is set as the Actual content in the validation params +// Validate simple-json report results according to the expected values and issue counts in the validation params. +// Content/Expected should be a formats.SimpleJsonResults in the validation params. +// If Expected is provided, the validation will check if the Actual content matches the expected results. +// If ExactResultsMatch is true, the validation will check exact values and not only the 'equal or grater' counts / existence of expected attributes. (For Integration tests with JFrog API, ExactResultsMatch should be set to false) func VerifySimpleJsonResults(t *testing.T, content string, params ValidationParams) { var results formats.SimpleJsonResults err := json.Unmarshal([]byte(content), &results) @@ -20,7 +22,10 @@ func VerifySimpleJsonResults(t *testing.T, content string, params ValidationPara ValidateCommandSimpleJsonOutput(t, params) } -// ValidateCommandSimpleJsonOutput validates SimpleJsonResults results. params.Actual (and params.Expected if provided) should be of type formats.SimpleJsonResults +// Validate simple-json report results according to the expected values and issue counts in the validation params. +// Actual/Expected content should be a formats.SimpleJsonResults in the validation params. +// If Expected is provided, the validation will check if the Actual content matches the expected results. +// If ExactResultsMatch is true, the validation will check exact values and not only the 'equal or grater' counts / existence of expected attributes. (For Integration tests with JFrog API, ExactResultsMatch should be set to false) func ValidateCommandSimpleJsonOutput(t *testing.T, params ValidationParams) { results, ok := params.Actual.(formats.SimpleJsonResults) if assert.True(t, ok, "Actual content is not of type formats.SimpleJsonResults") { @@ -34,6 +39,10 @@ func ValidateCommandSimpleJsonOutput(t *testing.T, params ValidationParams) { } } +// Validate simple-json report results according to the expected counts in the validation params. +// Actual content should be a formats.SimpleJsonResults in the validation params. +// If Expected is provided, the validation will check if the Actual content matches the expected results. +// If ExactResultsMatch is true, the validation will check exact values and not only the 'equal or grater' counts / existence of expected attributes. (For Integration tests with JFrog API, ExactResultsMatch should be set to false) func ValidateSimpleJsonIssuesCount(t *testing.T, params ValidationParams, results formats.SimpleJsonResults) { var applicableResults, undeterminedResults, notCoveredResults, notApplicableResults int for _, vuln := range results.Vulnerabilities { @@ -83,8 +92,8 @@ func ValidateSimpleJsonIssuesCount(t *testing.T, params ValidationParams, result } func ValidateSimpleJsonResults(t *testing.T, exactMatch bool, expected, actual formats.SimpleJsonResults) { - validateContent(t, exactMatch, StringValidation{Expected: expected.MultiScanId, Actual: actual.MultiScanId, Msg: "MultiScanId mismatch"}) - validateContent(t, false, NumberValidation[int]{Expected: len(expected.Errors), Actual: len(actual.Errors), Msg: "Errors count mismatch"}) + ValidateContent(t, exactMatch, StringValidation{Expected: expected.MultiScanId, Actual: actual.MultiScanId, Msg: "MultiScanId mismatch"}) + ValidateContent(t, false, NumberValidation[int]{Expected: len(expected.Errors), Actual: len(actual.Errors), Msg: "Errors count mismatch"}) // Validate vulnerabilities for _, expectedVulnerability := range expected.Vulnerabilities { vulnerability := getVulnerabilityOrViolationByIssueId(expectedVulnerability.IssueId, actual.Vulnerabilities) @@ -113,7 +122,7 @@ func getVulnerabilityOrViolationByIssueId(issueId string, content []formats.Vuln } func validateVulnerabilityOrViolationRow(t *testing.T, exactMatch bool, expected, actual formats.VulnerabilityOrViolationRow) { - validateContent(t, exactMatch, + ValidateContent(t, exactMatch, StringValidation{Expected: expected.Summary, Actual: actual.Summary, Msg: fmt.Sprintf("IssueId %s: Summary mismatch", expected.IssueId)}, StringValidation{Expected: expected.Severity, Actual: actual.Severity, Msg: fmt.Sprintf("IssueId %s: Severity mismatch", expected.IssueId)}, StringValidation{Expected: expected.Applicable, Actual: actual.Applicable, Msg: fmt.Sprintf("IssueId %s: Applicable mismatch", expected.IssueId)}, @@ -127,7 +136,7 @@ func validateVulnerabilityOrViolationRow(t *testing.T, exactMatch bool, expected ListValidation[string]{Expected: expected.FixedVersions, Actual: actual.FixedVersions, Msg: fmt.Sprintf("IssueId %s: FixedVersions mismatch", expected.IssueId)}, ) if ValidatePointersAndNotNil(t, exactMatch, PointerValidation[formats.JfrogResearchInformation]{Expected: expected.JfrogResearchInformation, Actual: actual.JfrogResearchInformation, Msg: fmt.Sprintf("IssueId %s: JfrogResearchInformation mismatch", expected.IssueId)}) { - validateContent(t, exactMatch, + ValidateContent(t, exactMatch, StringValidation{Expected: expected.JfrogResearchInformation.Summary, Actual: actual.JfrogResearchInformation.Summary, Msg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Summary mismatch", expected.IssueId)}, StringValidation{Expected: expected.JfrogResearchInformation.Severity, Actual: actual.JfrogResearchInformation.Severity, Msg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Severity mismatch", expected.IssueId)}, StringValidation{Expected: expected.JfrogResearchInformation.Remediation, Actual: actual.JfrogResearchInformation.Remediation, Msg: fmt.Sprintf("IssueId %s: JfrogResearchInformation.Remediation mismatch", expected.IssueId)}, @@ -157,11 +166,11 @@ func validateComponentRows(t *testing.T, issueId string, exactMatch bool, expect } func validateComponentRow(t *testing.T, issueId string, exactMatch bool, expected, actual formats.ComponentRow) { - validateContent(t, exactMatch, + ValidateContent(t, exactMatch, PointerValidation[formats.Location]{Expected: expected.Location, Actual: actual.Location, Msg: fmt.Sprintf("IssueId %s: Component %s:%s Location mismatch", issueId, expected.Name, expected.Version)}, ) if expected.Location != nil { - validateContent(t, exactMatch, StringValidation{Expected: expected.Location.File, Actual: actual.Location.File, Msg: fmt.Sprintf("IssueId %s: Component %s:%s Location.File mismatch", issueId, expected.Name, expected.Version)}) + ValidateContent(t, exactMatch, StringValidation{Expected: expected.Location.File, Actual: actual.Location.File, Msg: fmt.Sprintf("IssueId %s: Component %s:%s Location.File mismatch", issueId, expected.Name, expected.Version)}) } } @@ -188,14 +197,14 @@ func validateCveRows(t *testing.T, issueId string, exactMatch bool, expected, ac } func validateCveRow(t *testing.T, issueId string, exactMatch bool, expected, actual formats.CveRow) { - if !validateContent(t, exactMatch, + if !ValidateContent(t, exactMatch, StringValidation{Expected: expected.CvssV2, Actual: actual.CvssV2, Msg: fmt.Sprintf("IssueId %s: Cve %s: CvssV2 mismatch", issueId, expected.Id)}, StringValidation{Expected: expected.CvssV3, Actual: actual.CvssV3, Msg: fmt.Sprintf("IssueId %s: Cve %s: CvssV3 mismatch", issueId, expected.Id)}, ) { return } if ValidatePointersAndNotNil(t, exactMatch, PointerValidation[formats.Applicability]{Expected: expected.Applicability, Actual: actual.Applicability, Msg: fmt.Sprintf("IssueId %s: Cve %s: Applicability mismatch", issueId, expected.Id)}) { - validateContent(t, exactMatch, + ValidateContent(t, exactMatch, StringValidation{Expected: expected.Applicability.Status, Actual: actual.Applicability.Status, Msg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.Status mismatch", issueId, expected.Id)}, StringValidation{Expected: expected.Applicability.ScannerDescription, Actual: actual.Applicability.ScannerDescription, Msg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.ScannerDescription mismatch", issueId, expected.Id)}, ListValidation[formats.Evidence]{Expected: expected.Applicability.Evidence, Actual: actual.Applicability.Evidence, Msg: fmt.Sprintf("IssueId %s: Cve %s: Applicability.Evidence mismatch", issueId, expected.Id)}, diff --git a/utils/validations/test_validate_summary.go b/utils/validations/test_validate_summary.go index 112a1f2e..ea40fa6f 100644 --- a/utils/validations/test_validate_summary.go +++ b/utils/validations/test_validate_summary.go @@ -1,7 +1,6 @@ package validations import ( - "encoding/json" "testing" "github.com/jfrog/jfrog-cli-security/utils/formats" @@ -9,16 +8,10 @@ import ( "github.com/stretchr/testify/assert" ) -// Content should be a Json string of formats.SummaryResults and will be unmarshal. -// Value is set as the Actual content in the validation params -func VerifySummaryResults(t *testing.T, content string, params ValidationParams) { - var results formats.ResultsSummary - err := json.Unmarshal([]byte(content), &results) - assert.NoError(t, err) - params.Actual = results - ValidateCommandSummaryOutput(t, params) -} - +// Validate summary results according to the expected values and issue counts in the validation params. +// Content/Expected should be a formats.ResultsSummary in the validation params. +// If Expected is provided, the validation will check if the Actual content matches the expected results. +// If ExactResultsMatch is true, the validation will check exact values and not only the 'equal or grater' counts / existence of expected attributes. (For Integration tests with JFrog API, ExactResultsMatch should be set to false) func ValidateCommandSummaryOutput(t *testing.T, params ValidationParams) { results, ok := params.Actual.(formats.ResultsSummary) if assert.True(t, ok, "Actual content is not a formats.ResultsSummary") { diff --git a/utils/validations/test_validation.go b/utils/validations/test_validation.go index d093e4b9..04dafe74 100644 --- a/utils/validations/test_validation.go +++ b/utils/validations/test_validation.go @@ -20,6 +20,7 @@ func GetValidationCountErrMsg(what, where string, exactMatch bool, expectedCount return fmt.Sprintf(ErrCountFormat, " at least", expectedCount, what, where, actualCount, what) } +// ValidationParams holds validation/assertion parameters for tests. type ValidationParams struct { // The actual content to verify. Actual interface{} @@ -27,8 +28,7 @@ type ValidationParams struct { Expected interface{} // If provided, the test will check exact values and not only the minimum values / existence. ExactResultsMatch bool - - // Expected counts of values to validate. + // Expected issues for each type to check if the content has the correct amount of issues. Vulnerabilities int Licenses int SecurityViolations int @@ -43,11 +43,15 @@ type ValidationParams struct { Secrets int } +// Validation allows to validate/assert a content with expected values. +// Using the Validation interfaces implementations allows you to assert content for exact value or not exact match (changes base on the implementation). type Validation interface { Validate(t *testing.T, exactMatch bool) bool ErrMsgs(t *testing.T) []string } +// Validate a string content. +// Not ExactMatch: The actual content must not be empty if the expected content is not empty. type StringValidation struct { Expected string Actual string @@ -73,6 +77,8 @@ func (sv StringValidation) ErrMsgs(_ *testing.T) []string { return []string{sv.Msg} } +// NumberValidation validates the content of the given numbers. +// Not ExactMatch: The actual content must not be zero if the expected content is not zero. type NumberValidation[T any] struct { Expected T Actual T @@ -98,6 +104,8 @@ func (nvp NumberValidation[T]) ErrMsgs(_ *testing.T) []string { return []string{nvp.Msg} } +// PointerValidation validates the content of the given pointers. +// Not ExactMatch: The actual content must not be nil if the expected content is not nil. type PointerValidation[T any] struct { Expected *T Actual *T @@ -126,6 +134,8 @@ func (pvp PointerValidation[T]) ErrMsgs(t *testing.T) []string { return jsonErrMsg(t, pvp.Expected, pvp.Actual, pvp.Msg) } +// ListValidation validates the content of the given lists. +// Not ExactMatch: The expected content must be subset of the actual content. type ListValidation[T any] struct { Expected []T Actual []T @@ -165,9 +175,12 @@ func errMsg(expected, actual string, msg string) []string { return []string{msg, fmt.Sprintf("\n* Expected:\n'%s'\n\n* Actual:\n%s\n", expected, actual)} } -func validateContent(t *testing.T, exactMatch bool, pairs ...Validation) bool { - for _, pair := range pairs { - if !pair.Validate(t, exactMatch) { +// ValidateContent validates the content of the given Validations. +// If exactMatch is true, the content must match exactly. +// If at least one validation fails, the function returns false and stops validating the rest of the pairs. +func ValidateContent(t *testing.T, exactMatch bool, validations ...Validation) bool { + for _, validation := range validations { + if !validation.Validate(t, exactMatch) { return false } } From 3c9870632228bbd2d18402f36d98c2cddbc3029f Mon Sep 17 00:00:00 2001 From: attiasas Date: Wed, 11 Sep 2024 15:59:25 +0300 Subject: [PATCH 54/82] start add docker tests --- commands/scan/scan.go | 8 +- .../output/dockerscan/docker_results.json | 16278 ++++++++++++++++ .../output/dockerscan/docker_sarif.json | 0 .../output/dockerscan/docker_simple_json.json | 0 .../output/dockerscan/docker_summary.json | 77 + utils/formats/sarifutils/sarifutils.go | 45 + utils/formats/table.go | 1 + utils/results/common.go | 2 +- .../conversion/sarifparser/sarifparser.go | 10 +- .../simplejsonparser/simplejsonparser.go | 7 +- .../conversion/tableparser/tableparser.go | 1 + utils/results/output/resultwriter.go | 4 +- utils/results/results.go | 5 +- utils/validations/test_validate_sarif.go | 1 + 14 files changed, 16425 insertions(+), 14 deletions(-) create mode 100644 tests/testdata/output/dockerscan/docker_results.json create mode 100644 tests/testdata/output/dockerscan/docker_sarif.json create mode 100644 tests/testdata/output/dockerscan/docker_simple_json.json create mode 100644 tests/testdata/output/dockerscan/docker_summary.json diff --git a/commands/scan/scan.go b/commands/scan/scan.go index 86548d7c..e7335788 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -305,6 +305,10 @@ func (scanCmd *ScanCommand) RunAndRecordResults(cmdType utils.CommandType, recor err = errors.New("failed while trying to get Analyzer Manager: " + err.Error()) } + if err = recordResFunc(cmdResults); err != nil { + return err + } + if err = output.NewResultsWriter(cmdResults). SetOutputFormat(scanCmd.outputFormat). SetHasViolationContext(scanCmd.hasViolationContext()). @@ -316,10 +320,6 @@ func (scanCmd *ScanCommand) RunAndRecordResults(cmdType utils.CommandType, recor return } - if err = recordResFunc(cmdResults); err != nil { - return err - } - // If includeVulnerabilities is false it means that context was provided, so we need to check for build violations. // If user provided --fail=false, don't fail the build. if scanCmd.fail && !scanCmd.includeVulnerabilities { diff --git a/tests/testdata/output/dockerscan/docker_results.json b/tests/testdata/output/dockerscan/docker_results.json new file mode 100644 index 00000000..e5958783 --- /dev/null +++ b/tests/testdata/output/dockerscan/docker_results.json @@ -0,0 +1,16278 @@ +{ + "xray_version": "3.104.8", + "jas_entitled": true, + "command_type": "docker_image", + "targets": [ + { + "target": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1725978503-2625964325/image.tar", + "name": "nginx:latest", + "technology": "oci", + "sca_scans": { + "xray_scan": [ + { + "scan_id": "f1ca2a08-1d7b-4194-72be-7b84afc51fac", + "violations": [ + { + "summary": "loadImage() in tools/tiffcrop.c in LibTIFF through 4.5.0 has a heap-based use after free via a crafted TIFF image.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-522607", + "cves": [ + { + "cve": "CVE-2023-26965", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-26965", + "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", + "https://security.netapp.com/advisory/ntap-20230706-0009/", + "https://gitlab.com/libtiff/libtiff/-/merge_requests/472" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-522607\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "Use after free in libtiff's Tiffcrop may lead to code execution when parsing crafted images.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "Published PoC demonstrates crashing the tiffcrop CLI utility. Note that crashing tiffcrop has no security impact, since it is a forked CLI utility (will not crash parent process)." + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Although a crashing PoC is available, exploiting the vulnerability for remote code execution is currently only theoretically possible, and actual exploitation has not been demonstrated. Only some cases of use-after-free can be exploited for RCE.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must be able to upload a crafted TIFF image, which will then be processed by the `tiffcrop` CLI tool, for example -\n```bash\ntiffcrop -z 12,50,12,99:112,150,112,199 -e divided attacker_image.tiff output.tiff\n```", + "is_positive": true + } + ] + } + }, + { + "summary": "An out-of-memory flaw was found in libtiff that could be triggered by passing a crafted tiff file to the TIFFRasterScanlineSize64() API. This flaw allows a remote attacker to cause a denial of service via a crafted input with a size smaller than 379 KB.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-589394", + "cves": [ + { + "cve": "CVE-2023-52355", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://gitlab.com/libtiff/libtiff/-/issues/621", + "https://security-tracker.debian.org/tracker/CVE-2023-52355", + "https://bugzilla.redhat.com/show_bug.cgi?id=2251326", + "https://access.redhat.com/security/cve/CVE-2023-52355" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589394\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "Unbounded resource consumption in libtiff may lead to denial of service when parsing a crafted tiff file.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "PoC is included in the git issue discussing the problem." + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS attack complexity does not reflect the contextual prerequisites required to exploit the vulnerability.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "To exploit the vulnerability, the attacker must be able to upload a tiff file whose size will get checked by the vulnerable `TIFFRasterScanlineSize64()` function, and allocate memory (without any limitations) based on the results.", + "is_positive": true + } + ], + "remediation": "##### Development mitigations\n\nAs a workaround, users could implement checks, or use `TIFFOpenOptionsSetMaxSingleMemAlloc()`, to reject files that they consider to consume too many resources for their use case. For example -\n```\n// Allow 1MB single mem alloc\nTIFFOpenOptionsSetMaxSingleMemAlloc(\u0026opts, 1*1024*1024);\n```" + } + }, + { + "summary": "Integer overflow in libaom internal function img_alloc_helper can lead to heap buffer overflow. This function can be reached via 3 callers:\n\n\n * Calling aom_img_alloc() with a large value of the d_w, d_h, or align parameter may result in integer overflows in the calculations of buffer sizes and offsets and some fields of the returned aom_image_t struct may be invalid.\n * Calling aom_img_wrap() with a large value of the d_w, d_h, or align parameter may result in integer overflows in the calculations of buffer sizes and offsets and some fields of the returned aom_image_t struct may be invalid.\n * Calling aom_img_alloc_with_border() with a large value of the d_w, d_h, align, size_align, or border parameter may result in integer overflows in the calculations of buffer sizes and offsets and some fields of the returned aom_image_t struct may be invalid.", + "severity": "Critical", + "type": "security", + "components": { + "deb://debian:bookworm:libaom3:3.6.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libaom3:3.6.0-1", + "full_path": "libaom3:3.6.0-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-604193", + "cves": [ + { + "cve": "CVE-2024-5171", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-5171", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/6HYUEHZ35ZPY2EONVZCGO6LPT3AMLZCP/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/U5NRNCEYS246CYGOR32MF7OGKWOWER22/", + "https://issues.chromium.org/issues/332382766" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-604193\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "An integer overflow in libaom may lead to remote code execution when parsing malicious video data.", + "full_description": "[Libaom](https://aomedia.googlesource.com/aom/) is the reference encoder and decoder library for the `AV1` video codec. AV1 (AOMedia Video 1) is an open, royalty-free video coding format designed for video transmissions over the Internet. It was developed by the Alliance for Open Media (AOMedia), a consortium that includes firms like Google, Cisco, Microsoft, Mozilla, and Netflix.\nThe `aom` in libaom stands for `Alliance for Open Media`, and the library serves as a standard reference codebase that can be used to implement AV1 compression and decompression.\n\nProviding large values as the arguments to the `img_alloc_helper()` function, may lead to an integer overflow and a subsequent heap buffer overflow, which may lead to remote code execution.\n\n`img_alloc_helper()` function is an internal function that is used to allocate memory for an `aom_image_t` structure and its associated image data. This function is very useful when you need to manually create an image buffer that can then be used with the AOM codec for various operations like encoding or decoding.\n\nThe vulnerability cannot be exploited directly by calling `img_alloc_helper()` because it is an internal function. \n\nAlthough integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.\n\nTo exploit this vulnerability the following functions can be called with excessively large values as parameters:\n\n* `aom_img_alloc()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_wrap()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_alloc_with_border()` with a large value of the d_w, d_h, align, size_align, or border parameters.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "The published exploit demonstrates DoS." + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Although integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "The highest potential impact of this issue is severe (Remote Code Execution). Although no such impact has been demonstrated in practice." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker would need to find input propagating into the libaom encoding or decoding operations.", + "is_positive": true + } + ], + "remediation": "##### Development mitigations\n\nMake sure the following functions don't accept excessively large values as arguments to the following functions:\n\n* `aom_img_alloc()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_wrap()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_alloc_with_border()` with a large value of the d_w, d_h, align, size_align, or border parameters." + } + }, + { + "summary": "In MIT Kerberos 5 (aka krb5) before 1.21.3, an attacker can cause invalid memory reads during GSS message token handling by sending message tokens with invalid length fields.", + "severity": "Critical", + "type": "security", + "components": { + "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", + "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", + "full_path": "libk5crypto3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", + "full_path": "libkrb5-3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", + "full_path": "libkrb5support0:1.20.1-2+deb12u1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-607813", + "cves": [ + { + "cve": "CVE-2024-37371", + "cvss_v3_score": "9.1", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H" + } + ], + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-37371", + "https://web.mit.edu/kerberos/www/advisories/", + "https://github.com/krb5/krb5/commit/55fbf435edbe2e92dd8101669b1ce7144bc96fef" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-607813\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Libde265 v1.0.11 was discovered to contain a segmentation violation via the function decoder_context::process_slice_segment_header at decctx.cc.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-427847", + "cves": [ + { + "cve": "CVE-2023-27102", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://github.com/strukturag/libde265/issues/393", + "https://security-tracker.debian.org/tracker/CVE-2023-27102", + "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-427847\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the function find_exif_tag at /libheif/exif.cc.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libheif1:1.15.1-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", + "full_path": "libheif1:1.15.1-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-540355", + "cves": [ + { + "cve": "CVE-2023-49463", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://github.com/strukturag/libheif/issues/1042", + "https://github.com/strukturag/libheif", + "https://security-tracker.debian.org/tracker/CVE-2023-49463" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540355\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "An integer overflow in libheif leads to denial of service.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS score does not reflect the context dependent exploitation of this vulnerability.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "A proof-of-concept was published along with the vulnerability via (GitHub)[https://github.com/strukturag/libheif/issues/1042]." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "To successfully exploit this vulnerability an attacker needs to find a way to propagate input into the vulnerable functions `modify_exif_tag_if_it_exists(unsigned char*, unsigned int, unsigned short, unsigned short)` or `read_exif_orientation_tag(unsigned char const*, unsigned int)`.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Successful exploitation of this vulnerability leads to denial of service." + } + ] + } + }, + { + "summary": "A vulnerability was found that the response times to malformed ciphertexts in RSA-PSK ClientKeyExchange differ from response times of ciphertexts with correct PKCS#1 v1.5 padding.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libgnutls30:3.7.9-2": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", + "full_path": "libgnutls30:3.7.9-2" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-537103", + "cves": [ + { + "cve": "CVE-2023-5981", + "cvss_v3_score": "5.9", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N" + } + ], + "references": [ + "https://gnutls.org/security-new.html#GNUTLS-SA-2023-10-23", + "https://access.redhat.com/errata/RHSA-2024:0451", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNXKVR5YNUEBNHAHM5GSYKBZX4W2HMN2/", + "http://www.openwall.com/lists/oss-security/2024/01/19/3", + "https://access.redhat.com/errata/RHSA-2024:0533", + "https://bugzilla.redhat.com/show_bug.cgi?id=2248445", + "https://access.redhat.com/errata/RHSA-2024:0319", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/7ZEIOLORQ7N6WRPFXZSYDL2MC4LP7VFV/", + "https://access.redhat.com/errata/RHSA-2024:1383", + "https://access.redhat.com/errata/RHSA-2024:0399", + "https://security-tracker.debian.org/tracker/CVE-2023-5981", + "https://access.redhat.com/security/cve/CVE-2023-5981", + "https://access.redhat.com/errata/RHSA-2024:0155" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-537103\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "A flaw was found in shadow-utils. When asking for a new password, shadow-utils asks the password twice. If the password fails on the second attempt, shadow-utils fails in cleaning the buffer used to store the first entry. This may allow an attacker with enough access to retrieve the password from the memory.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1", + "full_path": "login:1:4.13+dfsg1-1+b1" + } + ] + ] + }, + "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1", + "full_path": "passwd:1:4.13+dfsg1-1+b1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-529509", + "cves": [ + { + "cve": "CVE-2023-4641", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N" + } + ], + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-4641", + "https://access.redhat.com/errata/RHSA-2024:2577", + "https://access.redhat.com/security/cve/CVE-2023-4641", + "https://access.redhat.com/errata/RHSA-2023:6632", + "https://bugzilla.redhat.com/show_bug.cgi?id=2215945", + "https://access.redhat.com/errata/RHSA-2024:0417", + "https://access.redhat.com/errata/RHSA-2023:7112" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-529509\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Libde265 v1.0.14 was discovered to contain a global buffer overflow vulnerability in the read_coding_unit function at slice.cc.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-540358", + "cves": [ + { + "cve": "CVE-2023-49468", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://lists.debian.org/debian-lts-announce/2023/12/msg00022.html", + "https://security-tracker.debian.org/tracker/CVE-2023-49468", + "https://github.com/strukturag/libde265/issues/432" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540358\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "A buffer overflow (in a global variable) in libde265 causes memory corruption leading to DoS and possibly code execution, when parsing attacker-supplied H.265 data.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "The provided PoC demonstrates a crash." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must be able to provide remote input that will be parsed by H.265, for example - `./dec265 attacker_input`.", + "is_positive": true + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "The impact of this vulnerability depends on the implementation of the vulnerable library. Substantial research has to be conducted to determine the exact impact this vulnerability could have. Code execution is not always achievable through a buffer overflow in a global variable.", + "is_positive": true + } + ] + } + }, + { + "summary": "A vulnerability was found in GnuTLS. The response times to malformed ciphertexts in RSA-PSK ClientKeyExchange differ from the response times of ciphertexts with correct PKCS#1 v1.5 padding. This issue may allow a remote attacker to perform a timing side-channel attack in the RSA-PSK key exchange, potentially leading to the leakage of sensitive data. CVE-2024-0553 is designated as an incomplete resolution for CVE-2023-5981.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libgnutls30:3.7.9-2": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", + "full_path": "libgnutls30:3.7.9-2" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-588549", + "cves": [ + { + "cve": "CVE-2024-0553", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N" + } + ], + "references": [ + "https://access.redhat.com/errata/RHSA-2024:2094", + "https://access.redhat.com/errata/RHSA-2024:0627", + "https://gitlab.com/gnutls/gnutls/-/issues/1522", + "https://access.redhat.com/errata/RHSA-2024:1383", + "https://access.redhat.com/errata/RHSA-2024:0796", + "http://www.openwall.com/lists/oss-security/2024/01/19/3", + "https://security.netapp.com/advisory/ntap-20240202-0011/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNXKVR5YNUEBNHAHM5GSYKBZX4W2HMN2/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/7ZEIOLORQ7N6WRPFXZSYDL2MC4LP7VFV/", + "https://lists.gnupg.org/pipermail/gnutls-help/2024-January/004841.html", + "https://access.redhat.com/errata/RHSA-2024:1108", + "https://lists.debian.org/debian-lts-announce/2024/02/msg00010.html", + "https://access.redhat.com/security/cve/CVE-2024-0553", + "https://access.redhat.com/errata/RHSA-2024:0533", + "https://access.redhat.com/errata/RHSA-2024:1082", + "https://bugzilla.redhat.com/show_bug.cgi?id=2258412", + "https://security-tracker.debian.org/tracker/CVE-2024-0553" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-588549\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "A design problem in GnuTLS may lead to RSA key brute force when attackers can cause many decryption operations.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue can be exploited by attackers over the network", + "description": "This vulnerability does not rely on timing to exploit, but rather on the server informing the client that decryption failed, hence it can be exploited remotely, completely disregarding latency issues." + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The given CVSS score does not take the context required to exploit the vulnerability into account.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "This CVE is only exploitable when all of the following conditions are met:\n\n1. The server must use `RSA` for key exchange.\n2. The server encrypts/decrypts `RSA` with `PKCS#1 v1.5` padding.\n3. The server informs the client when decryption fails.\n4. An attacker is on the same subnet, hijacks a session between the client and the server and manipulates the client data.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "A successful attack would compromise the server's private RSA key, allowing the attacker to decrypt any sniffed TLS traffic sent to or from the server from any host." + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Although Bleichenbacher's Attack is well documented today, a high technical understanding of cryptography is required to exploit it.", + "is_positive": true + } + ], + "remediation": "##### Development mitigations\n\n- When choosing a key exchange for your server, avoid using `RSA` and instead opt for the `Diffie-Hellman` key exchange, which provides forward secrecy.\nThis can be done by generating an ECDH key using OpenSSL:\n`openssl ecparam -name prime256v1 -genkey -noout -out mykey-prime256v1.pem`\nAnd giving the filepath of the keyfile to the `gnutls_certificate_set_x509_key_file` function - \n```c\ngnutls_certificate_set_x509_key_file(res, certfile, \"mykey-prime256v1.pem\", GNUTLS_X509_FMT_PEM);\n```\n\n- When using `RSA` for key exchange, use the `OAEP` padding scheme instead of `PKCS#1 v1.5`.\n\n- When using `RSA` and `PKCS#1` for key exchange, avoid informing the client of decryption failure." + } + }, + { + "summary": "libcurl's ASN1 parser code has the `GTime2str()` function, used for parsing an\nASN.1 Generalized Time field. If given an syntactically incorrect field, the\nparser might end up using -1 for the length of the *time fraction*, leading to\na `strlen()` getting performed on a pointer to a heap buffer area that is not\n(purposely) null terminated.\n\nThis flaw most likely leads to a crash, but can also lead to heap contents\ngetting returned to the application when\n[CURLINFO_CERTINFO](https://curl.se/libcurl/c/CURLINFO_CERTINFO.html) is used.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:curl:7.88.1-10+deb12u4": { + "fixed_versions": [ + "[7.88.1-10+deb12u7]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:curl:7.88.1-10+deb12u4", + "full_path": "curl:7.88.1-10+deb12u4" + } + ] + ] + }, + "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4", + "full_path": "libcurl4:7.88.1-10+deb12u4" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-617171", + "cves": [ + { + "cve": "CVE-2024-7264", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://hackerone.com/reports/2629968", + "https://security-tracker.debian.org/tracker/CVE-2024-7264", + "https://curl.se/docs/CVE-2024-7264.json", + "http://www.openwall.com/lists/oss-security/2024/07/31/1", + "https://curl.se/docs/CVE-2024-7264.html" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-617171\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Increasing the resolution of video frames, while performing a multi-threaded encode, can result in a heap overflow in av1_loop_restoration_dealloc().", + "severity": "Critical", + "type": "security", + "components": { + "deb://debian:bookworm:libaom3:3.6.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libaom3:3.6.0-1", + "full_path": "libaom3:3.6.0-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-585747", + "cves": [ + { + "cve": "CVE-2023-6879", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://aomedia.googlesource.com/aom/+/refs/tags/v3.7.1", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D6C2HN4T2S6GYNTAUXLH45LQZHK7QPHP/", + "https://crbug.com/aomedia/3491", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/AYONA2XSNFMXLAW4IHLFI5UVV3QRNG5K/", + "https://security-tracker.debian.org/tracker/CVE-2023-6879" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-585747\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "Heap buffer overread in the av1 module of the aom library can lead to denial of service when resizing frames under special conditions.", + "full_description": "AOM (Alliance for Open Media) is an open-source, royalty-free video codec library implemented in C, developed by the Alliance for Open Media, a consortium of technology companies and research institutions. The AOM library supports the AV1, VP9, and Thor video formats, providing high-quality video compression and is used for a variety of applications, including video streaming, video conferencing, and video editing.\nThe AV1 codec, developed by the Alliance for Open Media, is a state-of-the-art video compression technology that achieves exceptional efficiency while preserving high visual quality. The AOM library provides a comprehensive toolkit for working with AV1-encoded video streams, offering encoding, decoding, and manipulation capabilities.\n\nA vulnerability was found when using the `aom_codec_destroy()` function to clean up memory after resizing AV1 frames, specifically when:\n\n- Using AV1 codec (`aom_codec_av1_cx()`)\n- Utilizing multiple threads\n```\naom_codec_enc_cfg_t cfg;\naom_codec_enc_config_default(iface, \u0026cfg, AOM_USAGE_GOOD_QUALITY));\ncfg.g_threads = 4;\n```\n\nUnder these conditions, a Denial of Service (DoS) vulnerability emerges, manifesting as a heap buffer overread during object destruction.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "A public example of vulnerable AOM code exists, which shows how a DoS might be triggered." + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Under normal circumstances, the attacker cannot supply input which will trigger this vulnerability (either the vulnerable code exists or does not exist).", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The vulnerability triggers under the following conditions -\n- use of the AV1 codec (`aom_codec_av1_cx()`)\n- use of more than 1 thread:\n```\naom_codec_enc_cfg_t cfg;\naom_codec_enc_config_default(iface, \u0026cfg, AOM_USAGE_GOOD_QUALITY));\ncfg.g_threads = 4;\n```\n- cleaning the memory at the end of the encoding process (`aom_codec_destroy()`)", + "is_positive": true + } + ] + } + }, + { + "summary": "An issue was discovered in libxml2 before 2.11.7 and 2.12.x before 2.12.5. When using the XML Reader interface with DTD validation and XInclude expansion enabled, processing crafted XML documents can lead to an xmlValidatePopElement use-after-free.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1": { + "fixed_versions": [ + "[2.12.7+dfsg-1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1", + "full_path": "libxml2:2.9.14+dfsg-1.3~deb12u1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-589897", + "cves": [ + { + "cve": "CVE-2024-25062", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-25062", + "https://gitlab.gnome.org/GNOME/libxml2/-/tags", + "https://gitlab.gnome.org/GNOME/libxml2/-/issues/604" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589897\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "A use-after-free in libxml2 may lead to denial of service when parsing a crafted XML document with specific parser arguments.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "Exploiting this issue using static XML requires that the `XML_PARSE_XINCLUDE` (--xinclude) and the `XML_PARSE_VALIDATE` (--valid) flags are used.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Exploiting the vulnerability may lead to denial of service." + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS score does not take into account the contextual prerequisites required to exploit the vulnerability.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "A PoC that triggers the use-after-free is available in the Git issue." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must be able to control an XML file that is getting parsed by `xmlTextReaderRead()` with the xinclude and DTD validation options enabled. This can be achieved by passing both the `XML_PARSE_XINCLUDE` (--xinclude) and `XML_PARSE_VALIDATE` (--valid) flags when parsing the document.", + "is_positive": true + } + ] + } + }, + { + "summary": "A vulnerability, which was classified as critical, was found in Linux Kernel. This affects the function __mtk_ppe_check_skb of the file drivers/net/ethernet/mediatek/mtk_ppe.c of the component Ethernet Handler. The manipulation leads to use after free. It is recommended to apply a patch to fix this issue. The associated identifier of this vulnerability is VDB-211935.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-414609", + "cves": [ + { + "cve": "CVE-2022-3636", + "cvss_v3_score": "7.8", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://git.kernel.org/pub/scm/linux/kernel/git/pabeni/net-next.git/commit/?id=17a5f6a78dc7b8db385de346092d7d9f9dc24df6", + "https://vuldb.com/?id.211935", + "https://www.debian.org/security/2023/dsa-5333", + "https://security-tracker.debian.org/tracker/CVE-2022-3636" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-414609\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "An out-of-memory flaw was found in libtiff. Passing a crafted tiff file to TIFFOpen() API may allow a remote attacker to cause a denial of service via a craft input with size smaller than 379 KB.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-539830", + "cves": [ + { + "cve": "CVE-2023-6277", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://gitlab.com/libtiff/libtiff/-/issues/614", + "https://support.apple.com/kb/HT214123", + "https://support.apple.com/kb/HT214118", + "https://support.apple.com/kb/HT214122", + "https://support.apple.com/kb/HT214120", + "http://seclists.org/fulldisclosure/2024/Jul/21", + "http://seclists.org/fulldisclosure/2024/Jul/19", + "https://support.apple.com/kb/HT214117", + "http://seclists.org/fulldisclosure/2024/Jul/20", + "http://seclists.org/fulldisclosure/2024/Jul/23", + "https://support.apple.com/kb/HT214116", + "http://seclists.org/fulldisclosure/2024/Jul/16", + "https://support.apple.com/kb/HT214119", + "https://support.apple.com/kb/HT214124", + "http://seclists.org/fulldisclosure/2024/Jul/17", + "http://seclists.org/fulldisclosure/2024/Jul/22", + "http://seclists.org/fulldisclosure/2024/Jul/18", + "https://security.netapp.com/advisory/ntap-20240119-0002/", + "https://access.redhat.com/security/cve/CVE-2023-6277", + "https://bugzilla.redhat.com/show_bug.cgi?id=2251311", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/Y7ZGN2MZXJ6E57W3L4YBM3ZPAU3T7T5C/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/WJIN6DTSL3VODZUGWEUXLEL5DR53EZMV/", + "https://security-tracker.debian.org/tracker/CVE-2023-6277", + "https://gitlab.com/libtiff/libtiff/-/merge_requests/545" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-539830\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "In MIT Kerberos 5 (aka krb5) before 1.21.3, an attacker can modify the plaintext Extra Count field of a confidential GSS krb5 wrap token, causing the unwrapped token to appear truncated to the application.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", + "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", + "full_path": "libk5crypto3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", + "full_path": "libkrb5-3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", + "full_path": "libkrb5support0:1.20.1-2+deb12u1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-607812", + "cves": [ + { + "cve": "CVE-2024-37370", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N" + } + ], + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-37370", + "https://web.mit.edu/kerberos/www/advisories/", + "https://github.com/krb5/krb5/commit/55fbf435edbe2e92dd8101669b1ce7144bc96fef" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-607812\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Certain DNSSEC aspects of the DNS protocol (in RFC 4033, 4034, 4035, 6840, and related RFCs) allow remote attackers to cause a denial of service (CPU consumption) via one or more DNSSEC responses, aka the \"KeyTrap\" issue. One of the concerns is that, when there is a zone with many DNSKEY and RRSIG records, the protocol specification implies that an algorithm must evaluate all combinations of DNSKEY and RRSIG records.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", + "full_path": "libsystemd0:252.17-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", + "full_path": "libudev1:252.17-1~deb12u1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-590537", + "cves": [ + { + "cve": "CVE-2023-50387", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://security.netapp.com/advisory/ntap-20240307-0007/", + "http://www.openwall.com/lists/oss-security/2024/02/16/2", + "https://www.theregister.com/2024/02/13/dnssec_vulnerability_internet/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/6FV5O347JTX7P5OZA6NGO4MKTXRXMKOZ/", + "https://news.ycombinator.com/item?id=39367411", + "https://www.athene-center.de/aktuelles/key-trap", + "https://nlnetlabs.nl/news/2024/Feb/13/unbound-1.19.1-released/", + "https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2024q1/017430.html", + "https://www.isc.org/blogs/2024-bind-security-release/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/ZDZFMEKQTZ4L7RY46FCENWFB5MDT263R/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/RGS7JN6FZXUSTC2XKQHH27574XOULYYJ/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/TEXGOYGW7DBS3N2QSSQONZ4ENIRQEAPG/", + "https://bugzilla.suse.com/show_bug.cgi?id=1219823", + "https://lists.debian.org/debian-lts-announce/2024/05/msg00011.html", + "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-50387", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/HVRDSJVZKMCXKKPP6PNR62T7RWZ3YSDZ/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/PNNHZSZPG2E7NBMBNYPGHCFI4V4XRWNQ/", + "https://gitlab.nic.cz/knot/knot-resolver/-/releases/v5.7.1", + "https://www.athene-center.de/fileadmin/content/PDF/Technical_Report_KeyTrap.pdf", + "https://www.securityweek.com/keytrap-dns-attack-could-disable-large-parts-of-internet-researchers/", + "https://lists.debian.org/debian-lts-announce/2024/02/msg00006.html", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/SVYA42BLXUCIDLD35YIJPJSHDIADNYMP/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/BUIP7T7Z4T3UHLXFWG6XIVDP4GYPD3AI/", + "https://security-tracker.debian.org/tracker/CVE-2023-50387", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/IGSLGKUAQTW5JPPZCMF5YPEYALLRUZZ6/", + "https://kb.isc.org/docs/cve-2023-50387", + "https://docs.powerdns.com/recursor/security-advisories/powerdns-advisory-2024-01.html", + "https://news.ycombinator.com/item?id=39372384", + "http://www.openwall.com/lists/oss-security/2024/02/16/3", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/UQESRWMJCF4JEYJEAKLRM6CT55GLJAB7/", + "https://access.redhat.com/security/cve/CVE-2023-50387" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-590537\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "Unbounded resource consumption in the DNSSEC extension of the DNS protocol may lead to denial of service when resolving a malicious domain.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are either extremely common or nonexistent (always exploitable)", + "description": "To exploit the vulnerability, an attacker needs to make the victim resolver validate his malicious domain.\nNote - This flaw is derived from the DNSSEC standard, thus every implementation of DNSSEC that follows the standard is vulnerable." + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "The attacker needs to send a DNS query to the target resolver, requesting his malicious domain. The attack occurs when the resolver tries to validate the response from the DNS server." + }, + { + "name": "The issue has an exploit published", + "description": "A PoC was published, demonstrating denial of service." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Exploitation of the vulnerability causes high resource consumption, which leads to denial of service." + }, + { + "name": "The issue has a detailed technical explanation published, that can aid in exploit development", + "description": "A technically detailed writeup of this vulnerability (under the name \"keytrap\") was published by the research team, ATHENE-RESEARC." + } + ], + "remediation": "##### Deployment mitigations\n\nSince the vulnerability affects many different DNS resolvers, remediation is on a case-by-case basis." + } + }, + { + "summary": "libtiff 4.5.0 is vulnerable to Buffer Overflow in uv_encode() when libtiff reads a corrupted little-endian TIFF file and specifies the output to be big-endian.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-522650", + "cves": [ + { + "cve": "CVE-2023-26966", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", + "https://security-tracker.debian.org/tracker/CVE-2023-26966", + "https://gitlab.com/libtiff/libtiff/-/issues/530", + "https://gitlab.com/libtiff/libtiff/-/merge_requests/473" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-522650\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "VideoLAN dav1d before 1.2.0 has a thread_task.c race condition that can lead to an application crash, related to dav1d_decode_frame_exit.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libdav1d6:1.0.0-2": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libdav1d6:1.0.0-2", + "full_path": "libdav1d6:1.0.0-2" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-519404", + "cves": [ + { + "cve": "CVE-2023-32570", + "cvss_v3_score": "5.9", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/3WGSO7UMOF4MVLQ5H6KIV7OG6ONS377B/", + "https://security-tracker.debian.org/tracker/CVE-2023-32570", + "https://code.videolan.org/videolan/dav1d/-/tags/1.2.0", + "https://code.videolan.org/videolan/dav1d/-/commit/cf617fdae0b9bfabd27282854c8e81450d955efa", + "https://security.gentoo.org/glsa/202310-05", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LXZ6CUNJFDJLCFOZHY2TIGMCAEITLCRP/" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-519404\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the function UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libheif1:1.15.1-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", + "full_path": "libheif1:1.15.1-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-540356", + "cves": [ + { + "cve": "CVE-2023-49464", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://github.com/strukturag/libheif/issues/1044", + "https://security-tracker.debian.org/tracker/CVE-2023-49464" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540356\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "A use-after-free in libheif leads to denial of service and possibly remote code execution.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS score given to this CVE does not take into account the unlikely prerequisites for applicability of this vulnerability and the context required to exploit it.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "The fixing PR contains a denial of service PoC" + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker needs to find a remote input that propagates into the function `UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci`.", + "is_positive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "For this vulnerability to be applicable, `libheif1` needs to be compiled with the flag `-DWITH_UNCOMPRESSED_CODEC=ON`.\n\nWe found that this setting is enabled only in some package managers by default, but not all of them. In vanilla compilations, this flag is disabled by default.", + "is_positive": true + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Exploitation requires triggering a use-after-free beyond the scope of a single function. The use-after-free has not been proven to be able to cause code execution.", + "is_positive": true + } + ] + } + }, + { + "summary": "An issue was discovered in libexpat before 2.6.3. dtdCopy in xmlparse.c can have an integer overflow for nDefaultAtts on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", + "severity": "Critical", + "type": "security", + "components": { + "deb://debian:bookworm:libexpat1:2.5.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", + "full_path": "libexpat1:2.5.0-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-632611", + "cves": [ + { + "cve": "CVE-2024-45491", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-45491", + "https://github.com/libexpat/libexpat/pull/891", + "https://github.com/libexpat/libexpat/issues/888" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-632611\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "This flaw allows a malicious HTTP server to set \"super cookies\" in curl that\nare then passed back to more origins than what is otherwise allowed or\npossible. This allows a site to set cookies that then would get sent to\ndifferent and unrelated sites and domains.\n\nIt could do this by exploiting a mixed case flaw in curl's function that\nverifies a given cookie domain against the Public Suffix List (PSL). For\nexample a cookie could be set with `domain=co.UK` when the URL used a lower\ncase hostname `curl.co.uk`, even though `co.uk` is listed as a PSL domain.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:curl:7.88.1-10+deb12u4": { + "fixed_versions": [ + "[7.88.1-10+deb12u5]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:curl:7.88.1-10+deb12u4", + "full_path": "curl:7.88.1-10+deb12u4" + } + ] + ] + }, + "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4", + "full_path": "libcurl4:7.88.1-10+deb12u4" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-540279", + "cves": [ + { + "cve": "CVE-2023-46218", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N" + } + ], + "references": [ + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/3ZX3VW67N4ACRAPMV2QS2LVYGD7H2MVE/", + "https://security-tracker.debian.org/tracker/CVE-2023-46218", + "https://lists.debian.org/debian-lts-announce/2023/12/msg00015.html", + "https://curl.se/docs/CVE-2023-46218.html", + "https://hackerone.com/reports/2212193", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UOGXU25FMMT2X6UUITQ7EZZYMJ42YWWD/", + "https://security.netapp.com/advisory/ntap-20240125-0007/", + "https://www.debian.org/security/2023/dsa-5587" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540279\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "NGINX Open Source and NGINX Plus have a vulnerability in the ngx_http_mp4_module, which might allow an attacker to over-read NGINX worker memory resulting in its termination, using a specially crafted mp4 file. The issue only affects NGINX if it is built with the ngx_http_mp4_module and the mp4 directive is used in the configuration file. Additionally, the attack is possible only if an attacker can trigger the processing of a specially crafted mp4 file with the ngx_http_mp4_module.  Note: Software versions which have reached End of Technical Support (EoTS) are not evaluated.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:nginx:1.25.2-1~bookworm": { + "fixed_versions": [ + "[1.26.0-2]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:nginx:1.25.2-1~bookworm", + "full_path": "nginx:1.25.2-1~bookworm" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-619023", + "cves": [ + { + "cve": "CVE-2024-7347", + "cvss_v3_score": "4.7", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-7347", + "https://my.f5.com/manage/s/article/K000140529" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-619023\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Issue summary: A bug has been identified in the processing of key and\ninitialisation vector (IV) lengths. This can lead to potential truncation\nor overruns during the initialisation of some symmetric ciphers.\n\nImpact summary: A truncation in the IV can result in non-uniqueness,\nwhich could result in loss of confidentiality for some cipher modes.\n\nWhen calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or\nEVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after\nthe key and IV have been established. Any alterations to the key length,\nvia the \"keylen\" parameter or the IV length, via the \"ivlen\" parameter,\nwithin the OSSL_PARAM array will not take effect as intended, potentially\ncausing truncation or overreading of these values. The following ciphers\nand cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.\n\nFor the CCM, GCM and OCB cipher modes, truncation of the IV can result in\nloss of confidentiality. For example, when following NIST's SP 800-38D\nsection 8.2.1 guidance for constructing a deterministic IV for AES in\nGCM mode, truncation of the counter portion could lead to IV reuse.\n\nBoth truncations and overruns of the key and overruns of the IV will\nproduce incorrect results and could, in some cases, trigger a memory\nexception. However, these issues are not currently assessed as security\ncritical.\n\nChanging the key and/or IV lengths is not considered to be a common operation\nand the vulnerable API was recently introduced. Furthermore it is likely that\napplication developers will have spotted this problem during testing since\ndecryption would fail unless both peers in the communication were similarly\nvulnerable. For these reasons we expect the probability of an application being\nvulnerable to this to be quite low. However if an application is vulnerable then\nthis issue is considered very serious. For these reasons we have assessed this\nissue as Moderate severity overall.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\n\nThe OpenSSL 3.0 and 3.1 FIPS providers are...", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "fixed_versions": [ + "[3.0.11-1~deb12u2]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-534361", + "cves": [ + { + "cve": "CVE-2023-5363", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N" + } + ], + "references": [ + "https://security.netapp.com/advisory/ntap-20231027-0010/", + "https://www.openssl.org/news/secadv/20231024.txt", + "https://security-tracker.debian.org/tracker/CVE-2023-5363", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=5f69f5c65e483928c4b28ed16af6e5742929f1ee", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=0df40630850fb2740e6be6890bb905d3fc623b2d", + "https://www.debian.org/security/2023/dsa-5532", + "https://security.netapp.com/advisory/ntap-20240201-0004/", + "http://www.openwall.com/lists/oss-security/2023/10/24/1", + "https://security.netapp.com/advisory/ntap-20240201-0003/" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-534361\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "A design problem in OpenSSL 3.x may lead to data leakage when processing cipher parameters.", + "full_description": "OpenSSL is an open-source cryptographic library and toolset that provides a wide range of protocol supported and functions for secure communication, data encryption, digital certificates, and other cryptographic operations, widely used in various software applications and systems.\nIn cryptography, a block cipher is a symmetric key algorithm that encrypts fixed-size blocks of data, typically 64 or 128 bits, transforming each block into a corresponding ciphertext block using a key-specific permutation.\n\nA major problem with block ciphers, is that equal plaintext blocks get transformed to equal ciphertexts. This can be used for a known-plaintext attack, where an adversary possesses both the plaintext and its corresponding encrypted form, aiming to deduce the encryption key or gain insights into the encryption algorithm.\n\nTo counter this, we use an Initialization vector (IV), which is a random or unique input to a cryptographic algorithm used to alter the first block of the cipher, ensuring equal plaintext blocks won’t be transformed to equal ciphertexts.\n\nA vulnerability was found in OpenSSL 3.x, in certain situations, parameters such as key length or IV length, will be processed after the key and IV have been established, hence they will not take effect as intended, potentially causing truncation or overreading of these values, impacting the confidentiality of the encryption.\n\nWhen calling the functions `EVP_CipherInit_ex2`, `EVP_EncryptInit_ex2, or `EVP_DecryptInit_ex2` with an `OSSL_PARAM` array, changes to the `keylen` or `ivlen` parameters will only be processed after the IV and the key have been established.\n\nNote this impacts the following ciphers: RC2, RC4, RC5, and the following cipher modes: CCM, GCM, OCB.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The vulnerability is only applicable if the vulnerable functions `EVP_CipherInit_ex2`, `EVP_EncryptInit_ex2, or `EVP_DecryptInit_ex2` is called directly or indirectly with an `OSSL_PARAM` array that alters the `ivlen` and `keylen` parameters. Moreover, it only impacts the following ciphers: RC2, RC4, RC5, and the following cipher modes: CCM, GCM, OCB.", + "is_positive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "Changing the key or IV lengths is not considered a popular operation. Furthermore, the API only affects OpenSSL 3.x and it is likely the app developers have discovered the problem during testing, as it would have caused the decryption to fail.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The given CVSS score does not take into account the unlikely prerequisites and the context required to exploit this CVE.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "In the case that this vulnerability is exploited successfully, an attacker can read sensitive data as plaintext, breaking the encryption." + } + ] + } + }, + { + "summary": "The Key Distribution Center (KDC) in MIT Kerberos 5 (aka krb5) 1.9 allows remote attackers to cause a denial of service (NULL pointer dereference and daemon crash) via a malformed request packet that does not trigger a response packet.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", + "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", + "full_path": "libk5crypto3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", + "full_path": "libkrb5-3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", + "full_path": "libkrb5support0:1.20.1-2+deb12u1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-515010", + "cves": [ + { + "cve": "CVE-2011-0283", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P" + } + ], + "references": [ + "http://web.mit.edu/kerberos/advisories/MITKRB5-SA-2011-002.txt", + "http://www.securityfocus.com/bid/46272", + "http://securityreason.com/securityalert/8073", + "http://www.vupen.com/english/advisories/2011/0330", + "http://secunia.com/advisories/43260", + "http://www.securitytracker.com/id?1025037", + "http://www.securityfocus.com/archive/1/516299/100/0/threaded", + "https://security-tracker.debian.org/tracker/CVE-2011-0283" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-515010\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Libde265 v1.0.11 was discovered to contain a heap buffer overflow via the function derive_collocated_motion_vectors at motion.cc.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-427848", + "cves": [ + { + "cve": "CVE-2023-27103", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-27103", + "https://github.com/strukturag/libde265/issues/394", + "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-427848\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "A vulnerability was found in GnuTLS, where a cockpit (which uses gnuTLS) rejects a certificate chain with distributed trust. This issue occurs when validating a certificate chain with cockpit-certificate-ensure. This flaw allows an unauthenticated, remote client or attacker to initiate a denial of service attack.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libgnutls30:3.7.9-2": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", + "full_path": "libgnutls30:3.7.9-2" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-588550", + "cves": [ + { + "cve": "CVE-2024-0567", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://access.redhat.com/errata/RHSA-2024:2094", + "https://access.redhat.com/security/cve/CVE-2024-0567", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/7ZEIOLORQ7N6WRPFXZSYDL2MC4LP7VFV/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNXKVR5YNUEBNHAHM5GSYKBZX4W2HMN2/", + "https://bugzilla.redhat.com/show_bug.cgi?id=2258544", + "http://www.openwall.com/lists/oss-security/2024/01/19/3", + "https://security.netapp.com/advisory/ntap-20240202-0011/", + "https://access.redhat.com/errata/RHSA-2024:1383", + "https://lists.gnupg.org/pipermail/gnutls-help/2024-January/004841.html", + "https://access.redhat.com/errata/RHSA-2024:1082", + "https://security-tracker.debian.org/tracker/CVE-2024-0567", + "https://gitlab.com/gnutls/gnutls/-/issues/1521", + "https://access.redhat.com/errata/RHSA-2024:0533" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-588550\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "A design problem in GnuTLS may lead to denial of service when parsing a crafted certificate chain.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The given CVSS score does not take into account the prerequisites and context required to exploit the vulnerability.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The vulnerability is only exploitable if a GnuTLS client or server calls any of the following functions with externally-supplied input -\n\n- `gnutls_pcert_import_x509_list`\n\n- `gnutls_certificate_set_x509_key`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_mem`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_file`\n\n- `gnutls_privkey_import_url`\n\n- `gnutls_privkey_import_pkcs11_url`\n\n- `gnutls_read_key_file`\n\n- `gnutls_certificate_set_rawpk_key_file`\n\n- `gnutls_certificate_set_x509_key_file2`\n\n- `gnutls_certificate_set_x509_key_file`\n\n- `gnutls_pcert_list_import_x509_file`\n\n- `gnutls_certificate_set_x509_key_mem2`\n\n- `gnutls_certificate_set_x509_key_mem`\n\n- `gnutls_x509_crt_list_import`\n\n- `gnutls_pcert_list_import_x509_raw`\n\n- `gnutls_session_channel_binding`\n\n- `gnutls_x509_crt_list_import2`\n\n- `gnutls_x509_trust_list_add_trust_mem`\n\n- `gnutls_x509_trust_list_add_system_trust`\n\n- `gnutls_certificate_set_x509_system_trust`\n\n- `gnutls_certificate_set_x509_crl_mem`\n\n- `gnutls_certificate_set_x509_trust_mem`\n\n- `gnutls_x509_trust_list_add_trust_file`\n\n- `gnutls_certificate_set_x509_crl_file`\n\n- `gnutls_certificate_set_x509_trust_file`\n\n- `gnutls_x509_trust_list_add_trust_dir`\n\n- `gnutls_certificate_set_x509_trust_dir`\n\n- `gnutls_x509_trust_list_remove_trust_mem`\n\n- `gnutls_x509_trust_list_remove_trust_file`\n\n- `gnutls_x509_trust_list_verify_crt2`\n\n- `gnutls_x509_cert_verify_peers`\n\n- `gnutls_certificate_verify_peers`\n\n- `gnutls_certificate_verify_peers2`\n\n- `gnutls_certificate_verify_peers3`\n\n- `gnutls_pkcs7_verify`\n\n- `gnutls_ocsp_resp_verify`\n\n- `gnutls_x509_trust_list_verify_crt`", + "is_positive": true + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "is_positive": true + } + ] + } + }, + { + "summary": "When saving HSTS data to an excessively long file name, curl could end up\nremoving all contents, making subsequent requests using that file unaware of\nthe HSTS status they should otherwise use.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:curl:7.88.1-10+deb12u4": { + "fixed_versions": [ + "[7.88.1-10+deb12u5]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:curl:7.88.1-10+deb12u4", + "full_path": "curl:7.88.1-10+deb12u4" + } + ] + ] + }, + "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4", + "full_path": "libcurl4:7.88.1-10+deb12u4" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-540277", + "cves": [ + { + "cve": "CVE-2023-46219", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N" + } + ], + "references": [ + "https://www.debian.org/security/2023/dsa-5587", + "https://security.netapp.com/advisory/ntap-20240119-0007/", + "https://hackerone.com/reports/2236133", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UOGXU25FMMT2X6UUITQ7EZZYMJ42YWWD/", + "https://curl.se/docs/CVE-2023-46219.html", + "https://security-tracker.debian.org/tracker/CVE-2023-46219" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540277\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "libtiff 4.5.0 is vulnerable to Buffer Overflow via /libtiff/tools/tiffcrop.c:8499. Incorrect updating of buffer size after rotateImage() in tiffcrop cause heap-buffer-overflow and SEGV.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-523034", + "cves": [ + { + "cve": "CVE-2023-25433", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://gitlab.com/libtiff/libtiff/-/merge_requests/467", + "https://security-tracker.debian.org/tracker/CVE-2023-25433", + "https://gitlab.com/libtiff/libtiff/-/issues/520", + "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-523034\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "A null pointer dereference flaw was found in Libtiff via `tif_dirinfo.c`. This issue may allow an attacker to trigger memory allocation failures through certain means, such as restricting the heap space size or injecting faults, causing a segmentation fault. This can cause an application crash, eventually leading to a denial of service.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-617888", + "cves": [ + { + "cve": "CVE-2024-7006", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-7006", + "https://access.redhat.com/security/cve/CVE-2024-7006", + "https://bugzilla.redhat.com/show_bug.cgi?id=2302996", + "https://access.redhat.com/errata/RHSA-2024:6360" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-617888\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "libexpat through 2.5.0 allows a denial of service (resource consumption) because many full reparsings are required in the case of a large token for which multiple buffer fills are needed.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libexpat1:2.5.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", + "full_path": "libexpat1:2.5.0-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-589898", + "cves": [ + { + "cve": "CVE-2023-52425", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "http://www.openwall.com/lists/oss-security/2024/03/20/5", + "https://security.netapp.com/advisory/ntap-20240614-0003/", + "https://github.com/libexpat/libexpat/pull/789", + "https://lists.debian.org/debian-lts-announce/2024/04/msg00006.html", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/PNRIHC7DVVRAIWFRGV23Y6UZXFBXSQDB/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/WNUBSGZFEZOBHJFTAD42SAN4ATW2VEMV/", + "https://security-tracker.debian.org/tracker/CVE-2023-52425" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589898\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "A design problem in libexpat may lead to denial of service when parsing a crafted XML document with large tokens.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "A PoC demonstrating denial-of-service can be found in Expat's tests." + }, + { + "name": "The issue is trivial to exploit and does not require a published writeup or PoC", + "description": "The issue doesn't require any in-depth knowledge to trigger as a proof-of-concept exists in the official fix commit." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Exploitation of the vulnerability leads to high resource consumption which may lead to denial of service." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "Exploitation requires passing user-controlled input to an XML parsing function such as `XML_Parse`.", + "is_positive": true + } + ] + } + }, + { + "summary": "libxml2 through 2.11.5 has a use-after-free that can only occur after a certain memory allocation fails. This occurs in xmlUnlinkNode in tree.c. NOTE: the vendor's position is \"I don't think these issues are critical enough to warrant a CVE ID ... because an attacker typically can't control when memory allocations fail.\"", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1": { + "fixed_versions": [ + "[2.12.7+dfsg-1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1", + "full_path": "libxml2:2.9.14+dfsg-1.3~deb12u1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-533060", + "cves": [ + { + "cve": "CVE-2023-45322", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://gitlab.gnome.org/GNOME/libxml2/-/issues/583", + "http://www.openwall.com/lists/oss-security/2023/10/06/5", + "https://security-tracker.debian.org/tracker/CVE-2023-45322", + "https://gitlab.gnome.org/GNOME/libxml2/-/issues/344" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-533060\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Issue summary: Generating excessively long X9.42 DH keys or checking\nexcessively long X9.42 DH keys or parameters may be very slow.\n\nImpact summary: Applications that use the functions DH_generate_key() to\ngenerate an X9.42 DH key may experience long delays. Likewise, applications\nthat use DH_check_pub_key(), DH_check_pub_key_ex() or EVP_PKEY_public_check()\nto check an X9.42 DH key or X9.42 DH parameters may experience long delays.\nWhere the key or parameters that are being checked have been obtained from\nan untrusted source this may lead to a Denial of Service.\n\nWhile DH_check() performs all the necessary checks (as of CVE-2023-3817),\nDH_check_pub_key() doesn't make any of these checks, and is therefore\nvulnerable for excessively large P and Q parameters.\n\nLikewise, while DH_generate_key() performs a check for an excessively large\nP, it doesn't check for an excessively large Q.\n\nAn application that calls DH_generate_key() or DH_check_pub_key() and\nsupplies a key or parameters obtained from an untrusted source could be\nvulnerable to a Denial of Service attack.\n\nDH_generate_key() and DH_check_pub_key() are also called by a number of\nother OpenSSL functions. An application calling any of those other\nfunctions may similarly be affected. The other functions affected by this\nare DH_check_pub_key_ex(), EVP_PKEY_public_check(), and EVP_PKEY_generate().\n\nAlso vulnerable are the OpenSSL pkey command line application when using the\n\"-pubcheck\" option, as well as the OpenSSL genpkey command line application.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\n\nThe OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "fixed_versions": [ + "[3.0.13-1~deb12u1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-535129", + "cves": [ + { + "cve": "CVE-2023-5678", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L" + } + ], + "references": [ + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=34efaef6c103d636ab507a0cc34dca4d3aecc055", + "https://security.netapp.com/advisory/ntap-20231130-0010/", + "http://www.openwall.com/lists/oss-security/2024/03/11/1", + "https://security-tracker.debian.org/tracker/CVE-2023-5678", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=710fee740904b6290fef0dd5536fbcedbc38ff0c", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=db925ae2e65d0d925adef429afc37f75bd1c2017", + "https://www.openssl.org/news/secadv/20231106.txt", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=ddeb4b6c6d527e54ce9a99cba785c0f7776e54b6" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-535129\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "MiniZip in zlib through 1.3 has an integer overflow and resultant heap-based buffer overflow in zipOpenNewFileInZip4_64 via a long filename, comment, or extra field. NOTE: MiniZip is not a supported part of the zlib product. NOTE: pyminizip through 0.2.6 is also vulnerable because it bundles an affected zlib version, and exposes the applicable MiniZip code through its compress API.", + "severity": "Critical", + "type": "security", + "components": { + "deb://debian:bookworm:zlib1g:1:1.2.13.dfsg-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:zlib1g:1:1.2.13.dfsg-1", + "full_path": "zlib1g:1:1.2.13.dfsg-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-533715", + "cves": [ + { + "cve": "CVE-2023-45853", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "http://www.openwall.com/lists/oss-security/2024/01/24/10", + "http://www.openwall.com/lists/oss-security/2023/10/20/9", + "https://github.com/madler/zlib/blob/ac8f12c97d1afd9bafa9c710f827d40a407d3266/contrib/README.contrib#L1-L4", + "https://www.winimage.com/zLibDll/minizip.html", + "https://chromium.googlesource.com/chromium/src/+/de29dd6c7151d3cd37cb4cf0036800ddfb1d8b61", + "https://pypi.org/project/pyminizip/#history", + "https://lists.debian.org/debian-lts-announce/2023/11/msg00026.html", + "https://security.gentoo.org/glsa/202401-18", + "https://chromium.googlesource.com/chromium/src/+/d709fb23806858847131027da95ef4c548813356", + "https://github.com/madler/zlib/pull/843", + "https://security.netapp.com/advisory/ntap-20231130-0009/", + "https://security-tracker.debian.org/tracker/CVE-2023-45853" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-533715\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "A heap buffer overflow in zlib may lead to remote code execution when parsing a malicious archive.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "PoC demonstrates a heap overflow that crashes the application. Although not demonstrated, it is likely that an RCE exploit could be developed, since zip-processing may allow many heap-shaping primitives needed for a full RCE exploit." + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "An attacker could compromise a server that is using the `zlib` library to zip or unzip any files." + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS score does not reflect the context-dependent nature of this vulnerability.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Remote code execution." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find a way to upload a crafted zip archive, that is subsequently processed by the vulnerable `zipOpenNewFileInZip4_64` function.", + "is_positive": true + } + ], + "remediation": "##### Development mitigations\n\nMake sure that files with names larger than 65536 characters are not parsed using `zlib`.\n\nAlso, a fix currently exists in the `develop` branch of `zlib` and can be deployed manually." + } + }, + { + "summary": "NCurse v6.4-20230418 was discovered to contain a segmentation fault via the component _nc_wrap_entry().", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libtinfo6:6.4-4": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libtinfo6:6.4-4", + "full_path": "libtinfo6:6.4-4" + } + ] + ] + }, + "deb://debian:bookworm:ncurses-base:6.4-4": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:ncurses-base:6.4-4", + "full_path": "ncurses-base:6.4-4" + } + ] + ] + }, + "deb://debian:bookworm:ncurses-bin:6.4-4": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:ncurses-bin:6.4-4", + "full_path": "ncurses-bin:6.4-4" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-540521", + "cves": [ + { + "cve": "CVE-2023-50495", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LU4MYMKFEZQ5VSCVLRIZGDQOUW3T44GT/", + "https://lists.gnu.org/archive/html/bug-ncurses/2023-04/msg00020.html", + "https://security.netapp.com/advisory/ntap-20240119-0008/", + "https://security-tracker.debian.org/tracker/CVE-2023-50495", + "https://lists.gnu.org/archive/html/bug-ncurses/2023-04/msg00029.html" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540521\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "A vulnerability was found in libtiff due to multiple potential integer overflows in raw2tiff.c. This flaw allows remote attackers to cause a denial of service or possibly execute an arbitrary code via a crafted tiff image, which triggers a heap-based buffer overflow.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-529113", + "cves": [ + { + "cve": "CVE-2023-41175", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://bugzilla.redhat.com/show_bug.cgi?id=2235264", + "https://access.redhat.com/errata/RHSA-2024:2289", + "https://security-tracker.debian.org/tracker/CVE-2023-41175", + "https://access.redhat.com/security/cve/CVE-2023-41175" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-529113\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "An integer overflow in libtiff's raw2tiff may lead to remote code execution when parsing crafted images.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "For an attacker to exploit this vulnerability, `raw2tiff` has to be invoked with the `-l`, `-b` and `-w` flags. In addition to this, the attacker has to be able to supply a crafted TIFF file as input.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "PoC was published along with the git issue." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "The vulnerability leads to denial of service and possibly remote code execution." + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Although integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", + "is_positive": true + } + ] + } + }, + { + "summary": "A vulnerability was found in openldap. This security flaw causes a null pointer dereference in ber_memalloc_x() function.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5", + "full_path": "libldap-2.5-0:2.5.13+dfsg-5" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-520865", + "cves": [ + { + "cve": "CVE-2023-2953", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "http://seclists.org/fulldisclosure/2023/Jul/48", + "https://support.apple.com/kb/HT213845", + "http://seclists.org/fulldisclosure/2023/Jul/47", + "https://bugs.openldap.org/show_bug.cgi?id=9904", + "https://security-tracker.debian.org/tracker/CVE-2023-2953", + "https://support.apple.com/kb/HT213844", + "https://access.redhat.com/security/cve/CVE-2023-2953", + "https://security.netapp.com/advisory/ntap-20230703-0005/", + "http://seclists.org/fulldisclosure/2023/Jul/52", + "https://support.apple.com/kb/HT213843" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-520865\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", + "severity": "Critical", + "type": "security", + "components": { + "deb://debian:bookworm:libexpat1:2.5.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", + "full_path": "libexpat1:2.5.0-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-632612", + "cves": [ + { + "cve": "CVE-2024-45492", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://github.com/libexpat/libexpat/issues/889", + "https://security-tracker.debian.org/tracker/CVE-2024-45492", + "https://github.com/libexpat/libexpat/pull/892" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-632612\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", + "severity": "Critical", + "type": "security", + "components": { + "deb://debian:bookworm:libexpat1:2.5.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", + "full_path": "libexpat1:2.5.0-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-632613", + "cves": [ + { + "cve": "CVE-2024-45490", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://github.com/libexpat/libexpat/issues/887", + "https://security-tracker.debian.org/tracker/CVE-2024-45490", + "https://github.com/libexpat/libexpat/pull/890" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-632613\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Xmlsoft Libxml2 v2.11.0 was discovered to contain an out-of-bounds read via the xmlSAX2StartElement() function at /libxml2/SAX2.c. This vulnerability allows attackers to cause a Denial of Service (DoS) via supplying a crafted XML file. NOTE: the vendor's position is that the product does not support the legacy SAX1 interface with custom callbacks; there is a crash even without crafted input.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1": { + "fixed_versions": [ + "[2.12.7+dfsg-1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1", + "full_path": "libxml2:2.9.14+dfsg-1.3~deb12u1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-529332", + "cves": [ + { + "cve": "CVE-2023-39615", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-39615", + "https://gitlab.gnome.org/GNOME/libxml2/-/issues/535" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-529332\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL\nto crash leading to a potential Denial of Service attack\n\nImpact summary: Applications loading files in the PKCS12 format from untrusted\nsources might terminate abruptly.\n\nA file in PKCS12 format can contain certificates and keys and may come from an\nuntrusted source. The PKCS12 specification allows certain fields to be NULL, but\nOpenSSL does not correctly check for this case. This can lead to a NULL pointer\ndereference that results in OpenSSL crashing. If an application processes PKCS12\nfiles from an untrusted source using the OpenSSL APIs then that application will\nbe vulnerable to this issue.\n\nOpenSSL APIs that are vulnerable to this are: PKCS12_parse(),\nPKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes()\nand PKCS12_newpass().\n\nWe have also fixed a similar issue in SMIME_write_PKCS7(). However since this\nfunction is related to writing data we do not consider it security significant.\n\nThe FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "fixed_versions": [ + "[3.0.13-1~deb12u1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-589396", + "cves": [ + { + "cve": "CVE-2024-0727", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://github.com/openssl/openssl/commit/d135eeab8a5dbf72b3da5240bab9ddb7678dbd2c", + "https://github.openssl.org/openssl/extended-releases/commit/03b3941d60c4bce58fab69a0c22377ab439bc0e8", + "https://security-tracker.debian.org/tracker/CVE-2024-0727", + "https://github.openssl.org/openssl/extended-releases/commit/aebaa5883e31122b404e450732dc833dc9dee539", + "https://www.openssl.org/news/secadv/20240125.txt", + "https://security.netapp.com/advisory/ntap-20240208-0006/", + "https://github.com/openssl/openssl/commit/775acfdbd0c6af9ac855f34969cdab0c0c90844a", + "https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2", + "http://www.openwall.com/lists/oss-security/2024/03/11/1" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589396\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "A flaw was found in libtiff. A specially crafted tiff file can lead to a segmentation fault due to a buffer overflow in the Fax3Encode function in libtiff/tif_fax3.c, resulting in a denial of service.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-523187", + "cves": [ + { + "cve": "CVE-2023-3618", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-3618", + "https://support.apple.com/kb/HT214036", + "https://bugzilla.redhat.com/show_bug.cgi?id=2215865", + "https://security.netapp.com/advisory/ntap-20230824-0012/", + "https://access.redhat.com/security/cve/CVE-2023-3618", + "https://support.apple.com/kb/HT214037", + "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", + "https://support.apple.com/kb/HT214038" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-523187\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Integer overflow in the ReadDirectory function in tiffdump.c in tiffdump in LibTIFF before 3.9.5 allows remote attackers to cause a denial of service (application crash) or possibly have unspecified other impact via a crafted TIFF file containing a directory data structure with many directory entries.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-36369", + "cves": [ + { + "cve": "CVE-2010-4665", + "cvss_v2_score": "4.3", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:N/A:P" + } + ], + "references": [ + "http://www.securityfocus.com/bid/47338", + "http://lists.fedoraproject.org/pipermail/package-announce/2011-April/058478.html", + "http://www.debian.org/security/2012/dsa-2552", + "http://lists.opensuse.org/opensuse-security-announce/2011-05/msg00005.html", + "https://security-tracker.debian.org/tracker/CVE-2010-4665", + "http://security.gentoo.org/glsa/glsa-201209-02.xml", + "http://secunia.com/advisories/44271", + "http://ubuntu.com/usn/usn-1416-1", + "http://bugzilla.maptools.org/show_bug.cgi?id=2218", + "https://bugzilla.redhat.com/show_bug.cgi?id=695887", + "http://www.remotesensing.org/libtiff/v3.9.5.html", + "http://secunia.com/advisories/50726", + "http://openwall.com/lists/oss-security/2011/04/12/10" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-36369\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "AOMedia v3.0.0 to v3.5.0 was discovered to contain an invalid read memory access via the component assign_frame_buffer_p in av1/common/av1_common_int.h.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libaom3:3.6.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libaom3:3.6.0-1", + "full_path": "libaom3:3.6.0-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-529506", + "cves": [ + { + "cve": "CVE-2023-39616", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://bugs.chromium.org/p/aomedia/issues/detail?id=3372#c3", + "https://security-tracker.debian.org/tracker/CVE-2023-39616" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-529506\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "Invalid pointer dereference in libaom leads to denial of service when encoding crafted video data with nondefault configuration options set.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "The published exploit demonstrates DoS" + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The issue can be exploited by the `aomenc` CLI tool when called on arbitrary input file with the flag `--drop-frame=1` - \n`aomenc --passes=1 -h 1 -w 1 --drop-frame=1 --end-usage=cbr --buf-sz=1 -o /dev/null poc`\n \n\nAlternatively, the issue can be exploited through `libaom` when calling `aom_codec_enc_init` where the 3rd arg (`config`) has `dropframe_thresh == 1` + calling `aom_codec_encode` with external input to the 2nd arg (`img`)", + "is_positive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Exploiting the DoS via invocation of the `aomenc` CLI tool has minimal security impact, since exploitation will cause the `aomenc` forked utiliy process to crash (crashing a forked process has minimal security impact)\n\nThe issue can also be exploited via specific calls to `libaom`, however the configuration needed is extremely rare and crashing a video encoder usually does not have a high security impact.\n\nDebian classified this CVE as a \"minor issue\"", + "is_positive": true + } + ] + } + }, + { + "summary": "A heap-based buffer overflow was found in the __vsyslog_internal function of the glibc library. This function is called by the syslog and vsyslog functions. This issue occurs when the openlog function was not called, or called with the ident argument set to NULL, and the program name (the basename of argv[0]) is bigger than 1024 bytes, resulting in an application crash or local privilege escalation. This issue affects glibc 2.36 and newer.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-589627", + "cves": [ + { + "cve": "CVE-2023-6246", + "cvss_v3_score": "7.8", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D2FIH77VHY3KCRROCXOT6L27WMZXSJ2G/", + "https://security.netapp.com/advisory/ntap-20240216-0007/", + "https://security-tracker.debian.org/tracker/CVE-2023-6246", + "https://access.redhat.com/security/cve/CVE-2023-6246", + "http://packetstormsecurity.com/files/176931/glibc-qsort-Out-Of-Bounds-Read-Write.html", + "http://seclists.org/fulldisclosure/2024/Feb/5", + "https://www.openwall.com/lists/oss-security/2024/01/30/6", + "http://packetstormsecurity.com/files/176932/glibc-syslog-Heap-Based-Buffer-Overflow.html", + "https://bugzilla.redhat.com/show_bug.cgi?id=2249053", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MWQ6BZJ6CV5UAW4VZSKJ6TO4KIW2KWAQ/", + "https://security.gentoo.org/glsa/202402-01", + "http://seclists.org/fulldisclosure/2024/Feb/3" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589627\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "A heap buffer overflow in glibc may lead to local privilege escalation.", + "full_description": "[glibc](https://www.gnu.org/software/libc/) is the GNU C Library, a widely-used implementation of the C standard library.\n\nA vulnerability was identified in __vsyslog_internal(), which is called by the API functions `syslog()` and `vsyslog()` of glibc syslog functionality. Unprivileged users could gain full root access by manipulating syslog inputs.\n\nThe initial prerequisite for exploiting this local privilege escalation is a local SUID executable that contains calls to one of the vulnerable functions `syslog()` and `vsyslog()`. In order to exploit this, the attacker needs to control either argv[0], which typically holds the name of the program being executed, or the `openlog()` ident argument. \n\nAs explained in [Qualys’s research](https://qualys.com/2024/01/30/cve-2023-6246/syslog.txt), the identification string (LogTag) being NULL is essential for exploiting this issue. Thus, the `openlog()` function would need to either not be called, or called with NULL for the ident param for successful exploitation. \n\nIn Qualys’s research, they utilized a code path in the `su` program that doesn’t reach `openlog()`. Meaning the default user-controlled, argv[0] was used. Keep in mind another attack vector is possible in a different scenario when the user can control the ident arg of `openlog()`.\n\nSeeing as argv[0] is the name (path) of the running program, it is highly likely for a local attacker to be able to abuse this CVE for a local privilege escalation and unlikely that a remote attacker will have control over this argument for an RCE attack.\n\nQualys demonstrated a successful LPE exploit on Fedora. While no other public exploits are yet known, the threat landscape could evolve. It is likely possible to exploit this on other Linux distributions as well.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has multiple mentions in general media", + "description": "The vulnerability received extensive media coverage." + }, + { + "name": "The issue has a detailed technical explanation published, that can aid in exploit development", + "description": "This vulnerability has a through technical writeup, which also details an exploit." + }, + { + "name": "The prerequisites for exploiting the issue are either extremely common or nonexistent (always exploitable)", + "description": "As explained in the summary, the requirements to trigger the vulnerability are highly likely on default Linux machines that use a vulnerable version of glibc." + }, + { + "name": "The issue can only be exploited by an attacker that can execute code on the vulnerable machine (excluding exceedingly rare circumstances)", + "description": "This vulnerability requires local access to exploit. It is unlikely to be exploitable in remote scenarios as explained in the summary.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "This is a local privilege escalation vulnerability that could enable a local attacker to execute code as a root user." + } + ] + } + }, + { + "summary": "A segment fault (SEGV) flaw was found in libtiff that could be triggered by passing a crafted tiff file to the TIFFReadRGBATileExt() API. This flaw allows a remote attacker to cause a heap-buffer overflow, leading to a denial of service.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-589395", + "cves": [ + { + "cve": "CVE-2023-52356", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://access.redhat.com/errata/RHSA-2024:5079", + "https://support.apple.com/kb/HT214123", + "https://support.apple.com/kb/HT214118", + "http://seclists.org/fulldisclosure/2024/Jul/21", + "https://support.apple.com/kb/HT214122", + "https://support.apple.com/kb/HT214117", + "http://seclists.org/fulldisclosure/2024/Jul/20", + "http://seclists.org/fulldisclosure/2024/Jul/23", + "https://support.apple.com/kb/HT214116", + "http://seclists.org/fulldisclosure/2024/Jul/16", + "https://support.apple.com/kb/HT214119", + "https://support.apple.com/kb/HT214124", + "http://seclists.org/fulldisclosure/2024/Jul/17", + "https://support.apple.com/kb/HT214120", + "http://seclists.org/fulldisclosure/2024/Jul/19", + "http://seclists.org/fulldisclosure/2024/Jul/22", + "http://seclists.org/fulldisclosure/2024/Jul/18", + "https://lists.debian.org/debian-lts-announce/2024/03/msg00011.html", + "https://gitlab.com/libtiff/libtiff/-/issues/622", + "https://gitlab.com/libtiff/libtiff/-/merge_requests/546", + "https://security-tracker.debian.org/tracker/CVE-2023-52356", + "https://bugzilla.redhat.com/show_bug.cgi?id=2251344", + "https://access.redhat.com/security/cve/CVE-2023-52356" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589395\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "A heap buffer overflow in libtiff may lead to denial of service when parsing a crafted tiff image.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "To exploit the vulnerability, the attacker must be able to upload a maliciously crafted tiff image which will be parsed by the victim.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS score does not reflect the contextual prerequisites required to exploit the vulnerability.", + "is_positive": true + } + ] + } + }, + { + "summary": "An integer overflow was found in the __vsyslog_internal function of the glibc library. This function is called by the syslog and vsyslog functions. This issue occurs when these functions are called with a very long message, leading to an incorrect calculation of the buffer size to store the message, resulting in undefined behavior. This issue affects glibc 2.37 and newer.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-589628", + "cves": [ + { + "cve": "CVE-2023-6780", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L" + } + ], + "references": [ + "http://seclists.org/fulldisclosure/2024/Feb/3", + "https://security.gentoo.org/glsa/202402-01", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MWQ6BZJ6CV5UAW4VZSKJ6TO4KIW2KWAQ/", + "https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D2FIH77VHY3KCRROCXOT6L27WMZXSJ2G/", + "http://packetstormsecurity.com/files/176932/glibc-syslog-Heap-Based-Buffer-Overflow.html", + "https://www.openwall.com/lists/oss-security/2024/01/30/6", + "https://access.redhat.com/security/cve/CVE-2023-6780", + "https://security-tracker.debian.org/tracker/CVE-2023-6780", + "https://bugzilla.redhat.com/show_bug.cgi?id=2254396" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589628\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the function UncompressedImageCodec::decode_uncompressed_image.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libheif1:1.15.1-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", + "full_path": "libheif1:1.15.1-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-540353", + "cves": [ + { + "cve": "CVE-2023-49460", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-49460", + "https://github.com/strukturag/libheif/issues/1046" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540353\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "A NULL pointer dereference in libheif may lead to denial of service when parsing crafted images.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "A proof-of-concept was published in the report's GitHub Issue." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "To successfully exploit this vulnerability an attacker needs to find a way to propagate input into the vulnerable `UncompressedImageCodec::decode_uncompressed_image` function.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS score does not reflect the context dependent exploitation and impact of this vulnerability.", + "is_positive": true + } + ] + } + }, + { + "summary": "A null pointer dereference issue was found in Libtiff's tif_dir.c file. This issue may allow an attacker to pass a crafted TIFF image file to the tiffcp utility which triggers a runtime error that causes undefined behavior. This will result in an application crash, eventually leading to a denial of service.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-522698", + "cves": [ + { + "cve": "CVE-2023-2908", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://access.redhat.com/security/cve/CVE-2023-2908", + "https://gitlab.com/libtiff/libtiff/-/commit/9bd48f0dbd64fb94dc2b5b05238fde0bfdd4ff3f", + "https://gitlab.com/libtiff/libtiff/-/merge_requests/479", + "https://security.netapp.com/advisory/ntap-20230731-0004/", + "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", + "https://security-tracker.debian.org/tracker/CVE-2023-2908", + "https://bugzilla.redhat.com/show_bug.cgi?id=2218830" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-522698\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Multiple integer signedness errors in crypto/buffer/buffer.c in OpenSSL 0.9.8v allow remote attackers to conduct buffer overflow attacks, and cause a denial of service (memory corruption) or possibly have unspecified other impact, via crafted DER data, as demonstrated by an X.509 certificate or an RSA public key. NOTE: this vulnerability exists because of an incomplete fix for CVE-2012-2110.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-192416", + "cves": [ + { + "cve": "CVE-2012-2131", + "cvss_v2_score": "7.5", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P" + } + ], + "references": [ + "http://www.openwall.com/lists/oss-security/2012/04/24/1", + "http://secunia.com/advisories/48956", + "http://lists.apple.com/archives/security-announce/2013/Jun/msg00000.html", + "http://www.ubuntu.com/usn/USN-1428-1", + "http://secunia.com/advisories/48895", + "http://www-01.ibm.com/support/docview.wss?uid=ssg1S1004564", + "http://www.mandriva.com/security/advisories?name=MDVSA-2012:064", + "http://www.debian.org/security/2012/dsa-2454", + "http://www.openssl.org/news/secadv_20120424.txt", + "http://lists.opensuse.org/opensuse-security-announce/2012-05/msg00014.html", + "http://lists.opensuse.org/opensuse-security-announce/2012-09/msg00007.html", + "http://www.securitytracker.com/id?1026957", + "http://secunia.com/advisories/57353", + "http://marc.info/?l=bugtraq\u0026m=134039053214295\u0026w=2", + "https://security-tracker.debian.org/tracker/CVE-2012-2131", + "http://cvs.openssl.org/chngview?cn=22479", + "http://marc.info/?l=bugtraq\u0026m=133728068926468\u0026w=2", + "http://kb.juniper.net/InfoCenter/index?page=content\u0026id=JSA10673", + "https://exchange.xforce.ibmcloud.com/vulnerabilities/75099", + "http://www.securityfocus.com/bid/53212", + "http://lists.opensuse.org/opensuse-security-announce/2012-05/msg00015.html", + "http://support.apple.com/kb/HT5784" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-192416\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "A Segmentation fault caused by a floating point exception exists in libheif 1.15.1 using crafted heif images via the heif::Fraction::round() function in box.cc, which causes a denial of service.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libheif1:1.15.1-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", + "full_path": "libheif1:1.15.1-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-519184", + "cves": [ + { + "cve": "CVE-2023-29659", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/CKAE6NQBA3Q7GS6VTNDZRZZZVPPEFUEZ/", + "https://github.com/strukturag/libheif/issues/794", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LGKHDCS4HRZE3UGXYYDYPTIPNIBRLQ5L/", + "https://security-tracker.debian.org/tracker/CVE-2023-29659" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-519184\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "CPAN.pm before 2.35 does not verify TLS certificates when downloading distributions over HTTPS.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:perl-base:5.36.0-7": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:perl-base:5.36.0-7", + "full_path": "perl-base:5.36.0-7" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-515823", + "cves": [ + { + "cve": "CVE-2023-31484", + "cvss_v3_score": "8.1", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "http://www.openwall.com/lists/oss-security/2023/04/29/1", + "https://security.netapp.com/advisory/ntap-20240621-0007/", + "http://www.openwall.com/lists/oss-security/2023/05/03/5", + "http://www.openwall.com/lists/oss-security/2023/05/03/3", + "https://blog.hackeriet.no/perl-http-tiny-insecure-tls-default-affects-cpan-modules/", + "http://www.openwall.com/lists/oss-security/2023/05/07/2", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/BM6UW55CNFUTNGD5ZRKGUKKKFDJGMFHL/", + "https://metacpan.org/dist/CPAN/changes", + "https://security-tracker.debian.org/tracker/CVE-2023-31484", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LEGCEOKFJVBJ2QQ6S2H4NAEWTUERC7SB/", + "https://github.com/andk/cpanpm/pull/175", + "https://www.openwall.com/lists/oss-security/2023/04/18/14" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-515823\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "Missing TLS check in CPAN.pm allows man-in-the-middle attacks when downloading packages and may lead to code execution.", + "full_description": "[CPAN.pm](https://metacpan.org/pod/CPAN) is a Perl module and command-line tool that provides an automated and standardized way to download, install, and manage Perl modules and their dependencies from the Comprehensive Perl Archive Network (CPAN).\n[HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) is an HTTP client in Perl and a standalone CPAN module. By default, it does not verify TLS certificates. To enable it, the `verify_SSL=\u003e1` flag should be specified when initializing the `HTTP::Tiny` object. The problem identified in `HTTP::Tiny` has been assigned the CVE identifier `CVE-2023-31486` and serves as the underlying cause for the problem in `CPAN.pm`.\n\n`CPAN.pm` downloads and executes code through the `install` command followed by the package name.\nAlthough `CPAN.pm` downloads from `https://cpan.org`, it does not enable TLS certificate verification while using `HTTP::Tiny`, which could potentially allow an attacker to perform a man-in-the-middle attack by injecting malicious data that could be executed by CPAN.pm.\n\nExample of a vulnerable code:\n```\nuse CPAN;\ninstall DateTime\n```\n\nExample of a vulnerable command-line:\n```\ncpan install DateTime\n```", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue is trivial to exploit and does not require a published writeup or PoC", + "description": "Exploitation only requires an attacker to perform a man-in-the-middle attack (which is extensively documented) and provide the victim with a malicious package instead of the legitimate one." + }, + { + "name": "The issue has a detailed technical explanation published, that can aid in exploit development", + "description": "A technical write-up exists." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker should be in the network to perform a man-in-the-middle attack, and then provide a malicious package when the victim installs a new CPAN.pm package.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "This issue may lead to code execution." + }, + { + "name": "The issue can be exploited by attackers over the network" + } + ] + } + }, + { + "summary": "A vulnerability was found in systemd-resolved. This issue may allow systemd-resolved to accept records of DNSSEC-signed domains even when they have no signature, allowing man-in-the-middles (or the upstream DNS resolver) to manipulate records.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", + "full_path": "libsystemd0:252.17-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", + "full_path": "libudev1:252.17-1~deb12u1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-585478", + "cves": [ + { + "cve": "CVE-2023-7008", + "cvss_v3_score": "5.9", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N" + } + ], + "references": [ + "https://bugzilla.redhat.com/show_bug.cgi?id=2222672", + "https://github.com/systemd/systemd/issues/25676", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/4GMDEG5PKONWNHOEYSUDRT6JEOISRMN2/", + "https://access.redhat.com/errata/RHSA-2024:2463", + "https://access.redhat.com/security/cve/CVE-2023-7008", + "https://security-tracker.debian.org/tracker/CVE-2023-7008", + "https://access.redhat.com/errata/RHSA-2024:3203", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/QHNBXGKJWISJETTTDTZKTBFIBJUOSLKL/", + "https://bugzilla.redhat.com/show_bug.cgi?id=2222261" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-585478\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Issue summary: The POLY1305 MAC (message authentication code) implementation\ncontains a bug that might corrupt the internal state of applications running\non PowerPC CPU based platforms if the CPU provides vector instructions.\n\nImpact summary: If an attacker can influence whether the POLY1305 MAC\nalgorithm is used, the application state might be corrupted with various\napplication dependent consequences.\n\nThe POLY1305 MAC (message authentication code) implementation in OpenSSL for\nPowerPC CPUs restores the contents of vector registers in a different order\nthan they are saved. Thus the contents of some of these vector registers\nare corrupted when returning to the caller. The vulnerable code is used only\non newer PowerPC processors supporting the PowerISA 2.07 instructions.\n\nThe consequences of this kind of internal application state corruption can\nbe various - from no consequences, if the calling application does not\ndepend on the contents of non-volatile XMM registers at all, to the worst\nconsequences, where the attacker could get complete control of the application\nprocess. However unless the compiler uses the vector registers for storing\npointers, the most likely consequence, if any, would be an incorrect result\nof some application dependent calculations or a crash leading to a denial of\nservice.\n\nThe POLY1305 MAC algorithm is most frequently used as part of the\nCHACHA20-POLY1305 AEAD (authenticated encryption with associated data)\nalgorithm. The most common usage of this AEAD cipher is with TLS protocol\nversions 1.2 and 1.3. If this cipher is enabled on the server a malicious\nclient can influence whether this AEAD cipher is used. This implies that\nTLS server applications using OpenSSL can be potentially impacted. However\nwe are currently not aware of any concrete application that would be affected\nby this issue therefore we consider this a Low severity security issue.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "fixed_versions": [ + "[3.0.13-1~deb12u1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-588102", + "cves": [ + { + "cve": "CVE-2023-6129", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H" + } + ], + "references": [ + "https://security.netapp.com/advisory/ntap-20240426-0008/", + "https://security.netapp.com/advisory/ntap-20240426-0013/", + "http://www.openwall.com/lists/oss-security/2024/03/11/1", + "https://github.com/openssl/openssl/commit/f3fc5808fe9ff74042d639839610d03b8fdcc015", + "https://github.com/openssl/openssl/commit/050d26383d4e264966fb83428e72d5d48f402d35", + "https://security.netapp.com/advisory/ntap-20240216-0009/", + "https://www.openssl.org/news/secadv/20240109.txt", + "https://security-tracker.debian.org/tracker/CVE-2023-6129", + "https://github.com/openssl/openssl/commit/5b139f95c9a47a55a0c54100f3837b1eee942b04", + "https://security.netapp.com/advisory/ntap-20240503-0011/" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-588102\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Libde265 v1.0.14 was discovered to contain a heap-buffer-overflow vulnerability in the derive_spatial_luma_vector_prediction function at motion.cc.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-540366", + "cves": [ + { + "cve": "CVE-2023-49465", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://github.com/strukturag/libde265/issues/435", + "https://lists.debian.org/debian-lts-announce/2023/12/msg00022.html", + "https://security-tracker.debian.org/tracker/CVE-2023-49465" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540366\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "A non-proven heap buffer overflow in libde265 may lead to remote code execution when parsing attacker-supplied H.265 data.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "The attacker must be able to provide remote input that will be parsed by H.265, for example - `./dec265 attacker_input`.\nThe exploit only works on a small percent of executions, since the impact of parsing a malicious Atari DEGAS Elite bitmap file is contingent on the current heap state.", + "is_positive": true + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Although a PoC was linked to the issue, the maintainer was not able to reproduce the corruption. In addition, the heap buffer overflow was not proven to be able to cause remote code execution.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS does not take into account the non-trivial exploitation.", + "is_positive": true + } + ] + } + }, + { + "summary": "Libde265 v1.0.12 was discovered to contain multiple buffer overflows via the num_tile_columns and num_tile_row parameters in the function pic_parameter_set::dump.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-538327", + "cves": [ + { + "cve": "CVE-2023-43887", + "cvss_v3_score": "8.1", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H" + } + ], + "references": [ + "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html", + "https://security-tracker.debian.org/tracker/CVE-2023-43887", + "https://github.com/strukturag/libde265/issues/418", + "https://github.com/strukturag/libde265/commit/63b596c915977f038eafd7647d1db25488a8c133" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-538327\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "An out of bounds read in libde265 may lead to denial of service or data leakage when decoding attacker-supplied data in a non-default configuration.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker has to be able to decode crafted H.265 files with the non-default dump headers option enabled. For example - `./dec265 -d attacker_input`", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "The Github issue has a linked PoC." + }, + { + "name": "The issue has a detailed technical explanation published, that can aid in exploit development", + "description": "The Github issue carefully explains the vulnerability." + } + ] + } + }, + { + "summary": "**DISPUTED**A failure in the -fstack-protector feature in GCC-based toolchains \nthat target AArch64 allows an attacker to exploit an existing buffer \noverflow in dynamically-sized local variables in your application \nwithout this being detected. This stack-protector failure only applies \nto C99-style dynamically-sized local variables or those created using \nalloca(). The stack-protector operates as intended for statically-sized \nlocal variables.\n\nThe default behavior when the stack-protector \ndetects an overflow is to terminate your application, resulting in \ncontrolled loss of availability. An attacker who can exploit a buffer \noverflow without triggering the stack-protector might be able to change \nprogram flow control to cause an uncontrolled loss of availability or to\n go further and affect confidentiality or integrity. NOTE: The GCC project argues that this is a missed hardening bug and not a vulnerability by itself.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:gcc-12-base:12.2.0-14": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:gcc-12-base:12.2.0-14", + "full_path": "gcc-12-base:12.2.0-14" + } + ] + ] + }, + "deb://debian:bookworm:libgcc-s1:12.2.0-14": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libgcc-s1:12.2.0-14", + "full_path": "libgcc-s1:12.2.0-14" + } + ] + ] + }, + "deb://debian:bookworm:libstdc++6:12.2.0-14": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libstdc++6:12.2.0-14", + "full_path": "libstdc++6:12.2.0-14" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-531779", + "cves": [ + { + "cve": "CVE-2023-4039", + "cvss_v3_score": "4.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N" + } + ], + "references": [ + "https://github.com/metaredteam/external-disclosures/security/advisories/GHSA-x7ch-h5rf-w2mf", + "https://developer.arm.com/Arm%20Security%20Center/GCC%20Stack%20Protector%20Vulnerability%20AArch64", + "https://security-tracker.debian.org/tracker/CVE-2023-4039" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-531779\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Buffer Overflow vulnerability in strukturag libde265 v1.10.12 allows a local attacker to cause a denial of service via the slice_segment_header function in the slice.cc component.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-537162", + "cves": [ + { + "cve": "CVE-2023-47471", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://github.com/strukturag/libde265/commit/e36b4a1b0bafa53df47514c419d5be3e8916ebc7", + "https://security-tracker.debian.org/tracker/CVE-2023-47471", + "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html", + "https://github.com/strukturag/libde265/issues/426" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-537162\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "A memory leak flaw was found in Libtiff's tiffcrop utility. This issue occurs when tiffcrop operates on a TIFF image file, allowing an attacker to pass a crafted TIFF image file to tiffcrop utility, which causes this memory leak issue, resulting an application crash, eventually leading to a denial of service.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-532917", + "cves": [ + { + "cve": "CVE-2023-3576", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://access.redhat.com/security/cve/CVE-2023-3576", + "https://access.redhat.com/errata/RHSA-2023:6575", + "https://bugzilla.redhat.com/show_bug.cgi?id=2219340", + "https://lists.debian.org/debian-lts-announce/2024/03/msg00011.html", + "https://security-tracker.debian.org/tracker/CVE-2023-3576" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-532917\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "LibTIFF is vulnerable to an integer overflow. This flaw allows remote attackers to cause a denial of service (application crash) or possibly execute an arbitrary code via a crafted tiff image, which triggers a heap-based buffer overflow.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-529112", + "cves": [ + { + "cve": "CVE-2023-40745", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://access.redhat.com/security/cve/CVE-2023-40745", + "https://access.redhat.com/errata/RHSA-2024:2289", + "https://security-tracker.debian.org/tracker/CVE-2023-40745", + "https://security.netapp.com/advisory/ntap-20231110-0005/", + "https://bugzilla.redhat.com/show_bug.cgi?id=2235265" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-529112\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "An integer overflow in libtiff’s tiffcp may lead to remote code execution when parsing crafted images.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "For an attacker to exploit this vulnerability, `tiffcp` has to be invoked with the `-m` flag with an attacker-controlled value. In addition to this, the attacker has to be able to supply a crafted TIFF file as input.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "A PoC which demonstrates denial of service was published along with the git issue." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "The vulnerability leads to denial of service and possibly remote code execution." + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Although integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", + "is_positive": true + } + ] + } + }, + { + "summary": "linux-pam (aka Linux PAM) before 1.6.0 allows attackers to cause a denial of service (blocked login process) via mkfifo because the openat call (for protect_dir) lacks O_DIRECTORY.", + "severity": "Medium", + "type": "security", + "components": { + "deb://debian:bookworm:libpam-modules-bin:1.5.2-6+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libpam-modules-bin:1.5.2-6+deb12u1", + "full_path": "libpam-modules-bin:1.5.2-6+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libpam-modules:1.5.2-6+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libpam-modules:1.5.2-6+deb12u1", + "full_path": "libpam-modules:1.5.2-6+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libpam-runtime:1.5.2-6+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libpam-runtime:1.5.2-6+deb12u1", + "full_path": "libpam-runtime:1.5.2-6+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libpam0g:1.5.2-6+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libpam0g:1.5.2-6+deb12u1", + "full_path": "libpam0g:1.5.2-6+deb12u1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-588807", + "cves": [ + { + "cve": "CVE-2024-22365", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "https://github.com/linux-pam/linux-pam", + "http://www.openwall.com/lists/oss-security/2024/01/18/3", + "https://github.com/linux-pam/linux-pam/commit/031bb5a5d0d950253b68138b498dc93be69a64cb", + "https://github.com/linux-pam/linux-pam/releases/tag/v1.6.0", + "https://security-tracker.debian.org/tracker/CVE-2024-22365" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-588807\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "An off-by-one heap-based buffer overflow was found in the __vsyslog_internal function of the glibc library. This function is called by the syslog and vsyslog functions. This issue occurs when these functions are called with a message bigger than INT_MAX bytes, leading to an incorrect calculation of the buffer size to store the message, resulting in an application crash. This issue affects glibc 2.37 and newer.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-589629", + "cves": [ + { + "cve": "CVE-2023-6779", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" + } + ], + "references": [ + "http://seclists.org/fulldisclosure/2024/Feb/3", + "https://security.netapp.com/advisory/ntap-20240223-0006/", + "https://access.redhat.com/security/cve/CVE-2023-6779", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D2FIH77VHY3KCRROCXOT6L27WMZXSJ2G/", + "https://security-tracker.debian.org/tracker/CVE-2023-6779", + "https://www.openwall.com/lists/oss-security/2024/01/30/6", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MWQ6BZJ6CV5UAW4VZSKJ6TO4KIW2KWAQ/", + "https://bugzilla.redhat.com/show_bug.cgi?id=2254395", + "https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt", + "https://security.gentoo.org/glsa/202402-01", + "http://packetstormsecurity.com/files/176932/glibc-syslog-Heap-Based-Buffer-Overflow.html" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589629\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + }, + { + "summary": "Libde265 v1.0.14 was discovered to contain a heap-buffer-overflow vulnerability in the derive_combined_bipredictive_merging_candidates function at motion.cc.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-540357", + "cves": [ + { + "cve": "CVE-2023-49467", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://github.com/strukturag/libde265/issues/434", + "https://security-tracker.debian.org/tracker/CVE-2023-49467", + "https://lists.debian.org/debian-lts-announce/2023/12/msg00022.html" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540357\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "An infinite loop in libde265 leads to DoS when parsing attacker-supplied H.265 data.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS does not take into account the non-trivial exploitation prerequisites. In addition, the CVSS alludes that remote code execution is possible, while in reality the worst impact of exploiting this issue is denial of service.", + "is_positive": true + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "The attacker must be able to provide remote input that will be parsed by H.265, for example - `./dec265 attacker_input`.", + "is_positive": true + } + ] + } + }, + { + "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the component /libheif/exif.cc.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:libheif1:1.15.1-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", + "full_path": "libheif1:1.15.1-1" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-540354", + "cves": [ + { + "cve": "CVE-2023-49462", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://github.com/strukturag/libheif/issues/1043", + "https://security-tracker.debian.org/tracker/CVE-2023-49462" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540354\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "An integer overflow in libheif leads to denial of service.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "A proof-of-concept was published along with the vulnerability via (GitHub)[https://github.com/strukturag/libheif/issues/1043]." + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS score does not reflect the context dependent exploitation of this vulnerability.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "To successfully exploit this vulnerability an attacker needs to find a way to propagate input into the vulnerable functions `modify_exif_tag_if_it_exists(unsigned char*, unsigned int, unsigned short, unsigned short)` or `read_exif_orientation_tag(unsigned char const*, unsigned int)`.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Successful exploitation of this vulnerability leads to denial of service." + } + ] + } + }, + { + "summary": "A vulnerability was found in perl 5.30.0 through 5.38.0. This issue occurs when a crafted regular expression is compiled by perl, which can allow an attacker controlled byte buffer overflow in a heap allocated buffer.", + "severity": "High", + "type": "security", + "components": { + "deb://debian:bookworm:perl-base:5.36.0-7": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:perl-base:5.36.0-7", + "full_path": "perl-base:5.36.0-7" + } + ] + ] + } + }, + "watch_name": "Security_watch_1", + "issue_id": "XRAY-539839", + "cves": [ + { + "cve": "CVE-2023-47038", + "cvss_v3_score": "7.8", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" + } + ], + "references": [ + "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1056746", + "https://access.redhat.com/errata/RHSA-2024:3128", + "https://access.redhat.com/security/cve/CVE-2023-47038", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNEEWAACXQCEEAKSG7XX2D5YDRWLCIZJ/", + "https://security-tracker.debian.org/tracker/CVE-2023-47038", + "https://bugzilla.redhat.com/show_bug.cgi?id=2249523", + "https://perldoc.perl.org/perl5382delta#CVE-2023-47038-Write-past-buffer-end-via-illegal-user-defined-Unicode-property", + "https://access.redhat.com/errata/RHSA-2024:2228" + ], + "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-539839\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "extended_information": { + "short_description": "(non-issue) A heap buffer overflow in Perl leads to no impact when parsing a crafted regular expression.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "A test case is given, and is included in the Debian advisory:\n`perl -e 'qr/\\p{utf8::_perl_surrogate}/'`" + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "If the attacker can execute arbitrary Perl code, exploiting the vulnerability would offer no additional security impact.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS impact does not reflect the prerequisites required to exploit the vulnerability.", + "is_positive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker must be able to run Perl code which the victim executes.", + "is_positive": true + } + ] + } + } + ], + "vulnerabilities": [ + { + "cves": [ + { + "cve": "CVE-2019-3815", + "cvss_v2_score": "2.1", + "cvss_v2_vector": "CVSS:2.0/AV:L/AC:L/Au:N/C:N/I:N/A:P", + "cvss_v3_score": "3.3", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L", + "cwe": [ + "CWE-401" + ], + "cwe_details": { + "CWE-401": { + "name": "Missing Release of Memory after Effective Lifetime", + "description": "The product does not sufficiently track and release allocated memory after it has been used, which slowly consumes remaining memory." + } + } + } + ], + "summary": "A memory leak was discovered in the backport of fixes for CVE-2018-16864 in Red Hat Enterprise Linux. Function dispatch_message_real() in journald-server.c does not free the memory allocated by set_iovec_field_free() to store the `_CMDLINE=` entry. A local attacker may use this flaw to make systemd-journald crash. This issue only affects versions shipped with Red Hat Enterprise since v219-62.2.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", + "full_path": "libsystemd0:252.17-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", + "full_path": "libudev1:252.17-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-74739", + "references": [ + "https://access.redhat.com/errata/RHSA-2019:0201", + "https://lists.debian.org/debian-lts-announce/2019/03/msg00013.html", + "https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2019-3815", + "https://security-tracker.debian.org/tracker/CVE-2019-3815", + "https://access.redhat.com/errata/RHBA-2019:0327", + "http://www.securityfocus.com/bid/106632" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-50387", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-770" + ], + "cwe_details": { + "CWE-770": { + "name": "Allocation of Resources Without Limits or Throttling", + "description": "The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor." + } + } + } + ], + "summary": "Certain DNSSEC aspects of the DNS protocol (in RFC 4033, 4034, 4035, 6840, and related RFCs) allow remote attackers to cause a denial of service (CPU consumption) via one or more DNSSEC responses, aka the \"KeyTrap\" issue. One of the concerns is that, when there is a zone with many DNSKEY and RRSIG records, the protocol specification implies that an algorithm must evaluate all combinations of DNSKEY and RRSIG records.", + "severity": "High", + "components": { + "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", + "full_path": "libsystemd0:252.17-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", + "full_path": "libudev1:252.17-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-590537", + "references": [ + "https://security.netapp.com/advisory/ntap-20240307-0007/", + "http://www.openwall.com/lists/oss-security/2024/02/16/2", + "https://www.theregister.com/2024/02/13/dnssec_vulnerability_internet/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/6FV5O347JTX7P5OZA6NGO4MKTXRXMKOZ/", + "https://news.ycombinator.com/item?id=39367411", + "https://www.athene-center.de/aktuelles/key-trap", + "https://nlnetlabs.nl/news/2024/Feb/13/unbound-1.19.1-released/", + "https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2024q1/017430.html", + "https://www.isc.org/blogs/2024-bind-security-release/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/ZDZFMEKQTZ4L7RY46FCENWFB5MDT263R/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/RGS7JN6FZXUSTC2XKQHH27574XOULYYJ/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/TEXGOYGW7DBS3N2QSSQONZ4ENIRQEAPG/", + "https://bugzilla.suse.com/show_bug.cgi?id=1219823", + "https://lists.debian.org/debian-lts-announce/2024/05/msg00011.html", + "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-50387", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/HVRDSJVZKMCXKKPP6PNR62T7RWZ3YSDZ/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/PNNHZSZPG2E7NBMBNYPGHCFI4V4XRWNQ/", + "https://gitlab.nic.cz/knot/knot-resolver/-/releases/v5.7.1", + "https://www.athene-center.de/fileadmin/content/PDF/Technical_Report_KeyTrap.pdf", + "https://www.securityweek.com/keytrap-dns-attack-could-disable-large-parts-of-internet-researchers/", + "https://lists.debian.org/debian-lts-announce/2024/02/msg00006.html", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/SVYA42BLXUCIDLD35YIJPJSHDIADNYMP/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/BUIP7T7Z4T3UHLXFWG6XIVDP4GYPD3AI/", + "https://security-tracker.debian.org/tracker/CVE-2023-50387", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/IGSLGKUAQTW5JPPZCMF5YPEYALLRUZZ6/", + "https://kb.isc.org/docs/cve-2023-50387", + "https://docs.powerdns.com/recursor/security-advisories/powerdns-advisory-2024-01.html", + "https://news.ycombinator.com/item?id=39372384", + "http://www.openwall.com/lists/oss-security/2024/02/16/3", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/UQESRWMJCF4JEYJEAKLRM6CT55GLJAB7/", + "https://access.redhat.com/security/cve/CVE-2023-50387" + ], + "extended_information": { + "short_description": "Unbounded resource consumption in the DNSSEC extension of the DNS protocol may lead to denial of service when resolving a malicious domain.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are either extremely common or nonexistent (always exploitable)", + "description": "To exploit the vulnerability, an attacker needs to make the victim resolver validate his malicious domain.\nNote - This flaw is derived from the DNSSEC standard, thus every implementation of DNSSEC that follows the standard is vulnerable." + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "The attacker needs to send a DNS query to the target resolver, requesting his malicious domain. The attack occurs when the resolver tries to validate the response from the DNS server." + }, + { + "name": "The issue has an exploit published", + "description": "A PoC was published, demonstrating denial of service." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Exploitation of the vulnerability causes high resource consumption, which leads to denial of service." + }, + { + "name": "The issue has a detailed technical explanation published, that can aid in exploit development", + "description": "A technically detailed writeup of this vulnerability (under the name \"keytrap\") was published by the research team, ATHENE-RESEARC." + } + ], + "remediation": "##### Deployment mitigations\n\nSince the vulnerability affects many different DNS resolvers, remediation is on a case-by-case basis." + } + }, + { + "cves": [ + { + "cve": "CVE-2023-31437", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", + "cwe": [ + "CWE-354" + ], + "cwe_details": { + "CWE-354": { + "name": "Improper Validation of Integrity Check Value", + "description": "The product does not validate or incorrectly validates the integrity check values or checksums of a message. This may prevent it from detecting if the data has been modified or corrupted in transmission." + } + } + } + ], + "summary": "An issue was discovered in systemd 253. An attacker can modify a sealed log file such that, in some views, not all existing and sealed log messages are displayed. NOTE: the vendor reportedly sent \"a reply denying that any of the finding was a security vulnerability.\"", + "severity": "Low", + "components": { + "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", + "full_path": "libsystemd0:252.17-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", + "full_path": "libudev1:252.17-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-522311", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-31437", + "https://github.com/systemd/systemd/releases", + "https://github.com/kastel-security/Journald/blob/main/journald-publication.pdf", + "https://github.com/kastel-security/Journald" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-31439", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", + "cwe": [ + "CWE-354" + ], + "cwe_details": { + "CWE-354": { + "name": "Improper Validation of Integrity Check Value", + "description": "The product does not validate or incorrectly validates the integrity check values or checksums of a message. This may prevent it from detecting if the data has been modified or corrupted in transmission." + } + } + } + ], + "summary": "An issue was discovered in systemd 253. An attacker can modify the contents of past events in a sealed log file and then adjust the file such that checking the integrity shows no error, despite modifications. NOTE: the vendor reportedly sent \"a reply denying that any of the finding was a security vulnerability.\"", + "severity": "Low", + "components": { + "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", + "full_path": "libsystemd0:252.17-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", + "full_path": "libudev1:252.17-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-522310", + "references": [ + "https://github.com/kastel-security/Journald/blob/main/journald-publication.pdf", + "https://github.com/systemd/systemd/releases", + "https://github.com/systemd/systemd/pull/28885", + "https://security-tracker.debian.org/tracker/CVE-2023-31439", + "https://github.com/kastel-security/Journald" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-7008", + "cvss_v3_score": "5.9", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N", + "cwe": [ + "NVD-CWE-Other" + ] + } + ], + "summary": "A vulnerability was found in systemd-resolved. This issue may allow systemd-resolved to accept records of DNSSEC-signed domains even when they have no signature, allowing man-in-the-middles (or the upstream DNS resolver) to manipulate records.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", + "full_path": "libsystemd0:252.17-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", + "full_path": "libudev1:252.17-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-585478", + "references": [ + "https://bugzilla.redhat.com/show_bug.cgi?id=2222672", + "https://github.com/systemd/systemd/issues/25676", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/4GMDEG5PKONWNHOEYSUDRT6JEOISRMN2/", + "https://access.redhat.com/errata/RHSA-2024:2463", + "https://access.redhat.com/security/cve/CVE-2023-7008", + "https://security-tracker.debian.org/tracker/CVE-2023-7008", + "https://access.redhat.com/errata/RHSA-2024:3203", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/QHNBXGKJWISJETTTDTZKTBFIBJUOSLKL/", + "https://bugzilla.redhat.com/show_bug.cgi?id=2222261" + ] + }, + { + "cves": [ + { + "cve": "CVE-2013-4392", + "cvss_v2_score": "3.3", + "cvss_v2_vector": "CVSS:2.0/AV:L/AC:M/Au:N/C:P/I:P/A:N", + "cwe": [ + "CWE-59" + ], + "cwe_details": { + "CWE-59": { + "name": "Improper Link Resolution Before File Access ('Link Following')", + "description": "The product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource." + } + } + } + ], + "summary": "systemd, when updating file permissions, allows local users to change the permissions and SELinux security contexts for arbitrary files via a symlink attack on unspecified files.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", + "full_path": "libsystemd0:252.17-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", + "full_path": "libudev1:252.17-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-32874", + "references": [ + "http://www.openwall.com/lists/oss-security/2013/10/01/9", + "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=725357", + "https://security-tracker.debian.org/tracker/CVE-2013-4392", + "https://bugzilla.redhat.com/show_bug.cgi?id=859060" + ], + "extended_information": { + "short_description": "Improper update of SELinux labels in systemd allows root users to bypass SELinux via mount commands.", + "full_description": "[`systemd`](https://systemd.io) is a Linux software suite that provides numerous tools and system components, mainly a system and service manager, who runs on system startup.\n`systemd` before 239 improperly performs [`SELinux`](https://selinuxproject.org/) label updates when mounting drives, which makes it vulnerable to symlink attacks that may result in local privilege escalation. \n\n`SELinux` labels are used for access control, and help manage the access to resources based on user privilege. When `systemd` is required to mount user-specified drives or directories, it recursively updates the `SELinux` labels of the files inside the mounted directory tree, granting privileges to the mounting user to use those files. A vulnerability in `systemd`'s `label_fix` function allows an attacker to perform a symlink attack, in which a symlink to a sensitive resource exists in the mounted directory tree. This would result in the update of the `SELinux` label of the file pointed by the symlink, granting the mounting user privileges to use that resource, effectively bypassing SELinux.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are either extremely common or nonexistent (always exploitable)", + "description": "The issue affects many distributions by default, when SELinux is enabled" + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Bypass of SELinux by root users", + "is_positive": true + }, + { + "name": "The issue can only be exploited by an attacker that can execute code on the vulnerable machine (excluding exceedingly rare circumstances)", + "description": "A local attacker must create symbolic links and perform mount commands", + "is_positive": true + }, + { + "name": "The issue can only be exploited by an attacker with high privileges", + "description": "Mounting requires root privileges", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-31438", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", + "cwe": [ + "CWE-354" + ], + "cwe_details": { + "CWE-354": { + "name": "Improper Validation of Integrity Check Value", + "description": "The product does not validate or incorrectly validates the integrity check values or checksums of a message. This may prevent it from detecting if the data has been modified or corrupted in transmission." + } + } + } + ], + "summary": "An issue was discovered in systemd 253. An attacker can truncate a sealed log file and then resume log sealing such that checking the integrity shows no error, despite modifications. NOTE: the vendor reportedly sent \"a reply denying that any of the finding was a security vulnerability.\"", + "severity": "Low", + "components": { + "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", + "full_path": "libsystemd0:252.17-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", + "full_path": "libudev1:252.17-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-522309", + "references": [ + "https://github.com/kastel-security/Journald", + "https://github.com/systemd/systemd/releases", + "https://github.com/kastel-security/Journald/blob/main/journald-publication.pdf", + "https://security-tracker.debian.org/tracker/CVE-2023-31438", + "https://github.com/systemd/systemd/pull/28886" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-50495", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "NVD-CWE-noinfo" + ] + } + ], + "summary": "NCurse v6.4-20230418 was discovered to contain a segmentation fault via the component _nc_wrap_entry().", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libtinfo6:6.4-4": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libtinfo6:6.4-4", + "full_path": "libtinfo6:6.4-4" + } + ] + ] + }, + "deb://debian:bookworm:ncurses-base:6.4-4": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:ncurses-base:6.4-4", + "full_path": "ncurses-base:6.4-4" + } + ] + ] + }, + "deb://debian:bookworm:ncurses-bin:6.4-4": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:ncurses-bin:6.4-4", + "full_path": "ncurses-bin:6.4-4" + } + ] + ] + } + }, + "issue_id": "XRAY-540521", + "references": [ + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LU4MYMKFEZQ5VSCVLRIZGDQOUW3T44GT/", + "https://lists.gnu.org/archive/html/bug-ncurses/2023-04/msg00020.html", + "https://security.netapp.com/advisory/ntap-20240119-0008/", + "https://security-tracker.debian.org/tracker/CVE-2023-50495", + "https://lists.gnu.org/archive/html/bug-ncurses/2023-04/msg00029.html" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-2379" + } + ], + "summary": "libcurl skips the certificate verification for a QUIC connection under certain conditions, when built to use wolfSSL. If told to use an unknown/bad cipher or curve, the error path accidentally skips the verification and returns OK, thus ignoring any certificate problems.", + "severity": "Low", + "components": { + "deb://debian:bookworm:curl:7.88.1-10+deb12u4": { + "fixed_versions": [ + "[8.7.1-1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:curl:7.88.1-10+deb12u4", + "full_path": "curl:7.88.1-10+deb12u4" + } + ] + ] + }, + "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4", + "full_path": "libcurl4:7.88.1-10+deb12u4" + } + ] + ] + } + }, + "issue_id": "XRAY-596170", + "references": [ + "https://curl.se/docs/CVE-2024-2379.html", + "https://support.apple.com/kb/HT214120", + "https://support.apple.com/kb/HT214118", + "http://seclists.org/fulldisclosure/2024/Jul/19", + "https://support.apple.com/kb/HT214119", + "http://seclists.org/fulldisclosure/2024/Jul/18", + "http://seclists.org/fulldisclosure/2024/Jul/20", + "http://www.openwall.com/lists/oss-security/2024/03/27/2", + "https://hackerone.com/reports/2410774", + "https://security.netapp.com/advisory/ntap-20240531-0001/", + "https://security-tracker.debian.org/tracker/CVE-2024-2379", + "https://curl.se/docs/CVE-2024-2379.json" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-46219", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", + "cwe": [ + "CWE-311" + ], + "cwe_details": { + "CWE-311": { + "name": "Missing Encryption of Sensitive Data", + "description": "The product does not encrypt sensitive or critical information before storage or transmission." + } + } + } + ], + "summary": "When saving HSTS data to an excessively long file name, curl could end up\nremoving all contents, making subsequent requests using that file unaware of\nthe HSTS status they should otherwise use.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:curl:7.88.1-10+deb12u4": { + "fixed_versions": [ + "[7.88.1-10+deb12u5]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:curl:7.88.1-10+deb12u4", + "full_path": "curl:7.88.1-10+deb12u4" + } + ] + ] + }, + "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4", + "full_path": "libcurl4:7.88.1-10+deb12u4" + } + ] + ] + } + }, + "issue_id": "XRAY-540277", + "references": [ + "https://www.debian.org/security/2023/dsa-5587", + "https://security.netapp.com/advisory/ntap-20240119-0007/", + "https://hackerone.com/reports/2236133", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UOGXU25FMMT2X6UUITQ7EZZYMJ42YWWD/", + "https://curl.se/docs/CVE-2023-46219.html", + "https://security-tracker.debian.org/tracker/CVE-2023-46219" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-7264", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-125" + ], + "cwe_details": { + "CWE-125": { + "name": "Out-of-bounds Read", + "description": "The product reads data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "7" + } + ] + } + } + } + ], + "summary": "libcurl's ASN1 parser code has the `GTime2str()` function, used for parsing an\nASN.1 Generalized Time field. If given an syntactically incorrect field, the\nparser might end up using -1 for the length of the *time fraction*, leading to\na `strlen()` getting performed on a pointer to a heap buffer area that is not\n(purposely) null terminated.\n\nThis flaw most likely leads to a crash, but can also lead to heap contents\ngetting returned to the application when\n[CURLINFO_CERTINFO](https://curl.se/libcurl/c/CURLINFO_CERTINFO.html) is used.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:curl:7.88.1-10+deb12u4": { + "fixed_versions": [ + "[7.88.1-10+deb12u7]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:curl:7.88.1-10+deb12u4", + "full_path": "curl:7.88.1-10+deb12u4" + } + ] + ] + }, + "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4", + "full_path": "libcurl4:7.88.1-10+deb12u4" + } + ] + ] + } + }, + "issue_id": "XRAY-617171", + "references": [ + "https://hackerone.com/reports/2629968", + "https://security-tracker.debian.org/tracker/CVE-2024-7264", + "https://curl.se/docs/CVE-2024-7264.json", + "http://www.openwall.com/lists/oss-security/2024/07/31/1", + "https://curl.se/docs/CVE-2024-7264.html" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-46218", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N", + "cwe": [ + "NVD-CWE-noinfo" + ] + } + ], + "summary": "This flaw allows a malicious HTTP server to set \"super cookies\" in curl that\nare then passed back to more origins than what is otherwise allowed or\npossible. This allows a site to set cookies that then would get sent to\ndifferent and unrelated sites and domains.\n\nIt could do this by exploiting a mixed case flaw in curl's function that\nverifies a given cookie domain against the Public Suffix List (PSL). For\nexample a cookie could be set with `domain=co.UK` when the URL used a lower\ncase hostname `curl.co.uk`, even though `co.uk` is listed as a PSL domain.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:curl:7.88.1-10+deb12u4": { + "fixed_versions": [ + "[7.88.1-10+deb12u5]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:curl:7.88.1-10+deb12u4", + "full_path": "curl:7.88.1-10+deb12u4" + } + ] + ] + }, + "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4", + "full_path": "libcurl4:7.88.1-10+deb12u4" + } + ] + ] + } + }, + "issue_id": "XRAY-540279", + "references": [ + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/3ZX3VW67N4ACRAPMV2QS2LVYGD7H2MVE/", + "https://security-tracker.debian.org/tracker/CVE-2023-46218", + "https://lists.debian.org/debian-lts-announce/2023/12/msg00015.html", + "https://curl.se/docs/CVE-2023-46218.html", + "https://hackerone.com/reports/2212193", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UOGXU25FMMT2X6UUITQ7EZZYMJ42YWWD/", + "https://security.netapp.com/advisory/ntap-20240125-0007/", + "https://www.debian.org/security/2023/dsa-5587" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-3618", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-120" + ], + "cwe_details": { + "CWE-120": { + "name": "Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')", + "description": "The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow." + } + } + } + ], + "summary": "A flaw was found in libtiff. A specially crafted tiff file can lead to a segmentation fault due to a buffer overflow in the Fax3Encode function in libtiff/tif_fax3.c, resulting in a denial of service.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-523187", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-3618", + "https://support.apple.com/kb/HT214036", + "https://bugzilla.redhat.com/show_bug.cgi?id=2215865", + "https://security.netapp.com/advisory/ntap-20230824-0012/", + "https://access.redhat.com/security/cve/CVE-2023-3618", + "https://support.apple.com/kb/HT214037", + "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", + "https://support.apple.com/kb/HT214038" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-26965", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "loadImage() in tools/tiffcrop.c in LibTIFF through 4.5.0 has a heap-based use after free via a crafted TIFF image.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-522607", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-26965", + "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", + "https://security.netapp.com/advisory/ntap-20230706-0009/", + "https://gitlab.com/libtiff/libtiff/-/merge_requests/472" + ], + "extended_information": { + "short_description": "Use after free in libtiff's Tiffcrop may lead to code execution when parsing crafted images.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "Published PoC demonstrates crashing the tiffcrop CLI utility. Note that crashing tiffcrop has no security impact, since it is a forked CLI utility (will not crash parent process)." + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Although a crashing PoC is available, exploiting the vulnerability for remote code execution is currently only theoretically possible, and actual exploitation has not been demonstrated. Only some cases of use-after-free can be exploited for RCE.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must be able to upload a crafted TIFF image, which will then be processed by the `tiffcrop` CLI tool, for example -\n```bash\ntiffcrop -z 12,50,12,99:112,150,112,199 -e divided attacker_image.tiff output.tiff\n```", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2022-3636", + "cvss_v3_score": "7.8", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-119" + ], + "cwe_details": { + "CWE-119": { + "name": "Improper Restriction of Operations within the Bounds of a Memory Buffer", + "description": "The product performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "17" + } + ] + } + } + } + ], + "summary": "A vulnerability, which was classified as critical, was found in Linux Kernel. This affects the function __mtk_ppe_check_skb of the file drivers/net/ethernet/mediatek/mtk_ppe.c of the component Ethernet Handler. The manipulation leads to use after free. It is recommended to apply a patch to fix this issue. The associated identifier of this vulnerability is VDB-211935.", + "severity": "High", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-414609", + "references": [ + "https://git.kernel.org/pub/scm/linux/kernel/git/pabeni/net-next.git/commit/?id=17a5f6a78dc7b8db385de346092d7d9f9dc24df6", + "https://vuldb.com/?id.211935", + "https://www.debian.org/security/2023/dsa-5333", + "https://security-tracker.debian.org/tracker/CVE-2022-3636" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-6277", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-400" + ], + "cwe_details": { + "CWE-400": { + "name": "Uncontrolled Resource Consumption", + "description": "The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources." + } + } + } + ], + "summary": "An out-of-memory flaw was found in libtiff. Passing a crafted tiff file to TIFFOpen() API may allow a remote attacker to cause a denial of service via a craft input with size smaller than 379 KB.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-539830", + "references": [ + "https://gitlab.com/libtiff/libtiff/-/issues/614", + "https://support.apple.com/kb/HT214123", + "https://support.apple.com/kb/HT214118", + "https://support.apple.com/kb/HT214122", + "https://support.apple.com/kb/HT214120", + "http://seclists.org/fulldisclosure/2024/Jul/21", + "http://seclists.org/fulldisclosure/2024/Jul/19", + "https://support.apple.com/kb/HT214117", + "http://seclists.org/fulldisclosure/2024/Jul/20", + "http://seclists.org/fulldisclosure/2024/Jul/23", + "https://support.apple.com/kb/HT214116", + "http://seclists.org/fulldisclosure/2024/Jul/16", + "https://support.apple.com/kb/HT214119", + "https://support.apple.com/kb/HT214124", + "http://seclists.org/fulldisclosure/2024/Jul/17", + "http://seclists.org/fulldisclosure/2024/Jul/22", + "http://seclists.org/fulldisclosure/2024/Jul/18", + "https://security.netapp.com/advisory/ntap-20240119-0002/", + "https://access.redhat.com/security/cve/CVE-2023-6277", + "https://bugzilla.redhat.com/show_bug.cgi?id=2251311", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/Y7ZGN2MZXJ6E57W3L4YBM3ZPAU3T7T5C/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/WJIN6DTSL3VODZUGWEUXLEL5DR53EZMV/", + "https://security-tracker.debian.org/tracker/CVE-2023-6277", + "https://gitlab.com/libtiff/libtiff/-/merge_requests/545" + ] + }, + { + "cves": [ + { + "cve": "CVE-2017-16232", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-772" + ], + "cwe_details": { + "CWE-772": { + "name": "Missing Release of Resource after Effective Lifetime", + "description": "The product does not release a resource after its effective lifetime has ended, i.e., after the resource is no longer needed." + } + } + } + ], + "summary": "LibTIFF 4.0.8 has multiple memory leak vulnerabilities, which allow attackers to cause a denial of service (memory consumption), as demonstrated by tif_open.c, tif_lzw.c, and tif_aux.c. NOTE: Third parties were unable to reproduce the issue", + "severity": "Low", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-59579", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2017-16232", + "http://lists.opensuse.org/opensuse-security-announce/2018-01/msg00036.html", + "http://www.securityfocus.com/bid/101696", + "http://seclists.org/fulldisclosure/2018/Dec/47", + "http://www.openwall.com/lists/oss-security/2017/11/01/7", + "http://seclists.org/fulldisclosure/2018/Dec/32", + "http://www.openwall.com/lists/oss-security/2017/11/01/3", + "http://packetstormsecurity.com/files/150896/LibTIFF-4.0.8-Memory-Leak.html", + "http://lists.opensuse.org/opensuse-security-announce/2018-01/msg00041.html", + "http://www.openwall.com/lists/oss-security/2017/11/01/8", + "http://www.openwall.com/lists/oss-security/2017/11/01/11" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-2908", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-476" + ], + "cwe_details": { + "CWE-476": { + "name": "NULL Pointer Dereference", + "description": "A NULL pointer dereference occurs when the application dereferences a pointer that it expects to be valid, but is NULL, typically causing a crash or exit.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "12" + } + ] + } + } + } + ], + "summary": "A null pointer dereference issue was found in Libtiff's tif_dir.c file. This issue may allow an attacker to pass a crafted TIFF image file to the tiffcp utility which triggers a runtime error that causes undefined behavior. This will result in an application crash, eventually leading to a denial of service.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-522698", + "references": [ + "https://access.redhat.com/security/cve/CVE-2023-2908", + "https://gitlab.com/libtiff/libtiff/-/commit/9bd48f0dbd64fb94dc2b5b05238fde0bfdd4ff3f", + "https://gitlab.com/libtiff/libtiff/-/merge_requests/479", + "https://security.netapp.com/advisory/ntap-20230731-0004/", + "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", + "https://security-tracker.debian.org/tracker/CVE-2023-2908", + "https://bugzilla.redhat.com/show_bug.cgi?id=2218830" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-26966", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-120" + ], + "cwe_details": { + "CWE-120": { + "name": "Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')", + "description": "The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow." + } + } + } + ], + "summary": "libtiff 4.5.0 is vulnerable to Buffer Overflow in uv_encode() when libtiff reads a corrupted little-endian TIFF file and specifies the output to be big-endian.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-522650", + "references": [ + "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", + "https://security-tracker.debian.org/tracker/CVE-2023-26966", + "https://gitlab.com/libtiff/libtiff/-/issues/530", + "https://gitlab.com/libtiff/libtiff/-/merge_requests/473" + ] + }, + { + "cves": [ + { + "cve": "CVE-2017-17973", + "cvss_v2_score": "6.8", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:P/I:P/A:P", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-416" + ], + "cwe_details": { + "CWE-416": { + "name": "Use After Free", + "description": "Referencing memory after it has been freed can cause a program to crash, use unexpected values, or execute code.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "4" + } + ] + } + } + } + ], + "summary": "In LibTIFF 4.0.8, there is a heap-based use-after-free in the t2p_writeproc function in tiff2pdf.c. NOTE: there is a third-party report of inability to reproduce this issue", + "severity": "Low", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-60516", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2017-17973", + "https://bugzilla.novell.com/show_bug.cgi?id=1074318", + "http://www.securityfocus.com/bid/102331", + "https://bugzilla.redhat.com/show_bug.cgi?id=1530912", + "http://bugzilla.maptools.org/show_bug.cgi?id=2769" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-52355", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "An out-of-memory flaw was found in libtiff that could be triggered by passing a crafted tiff file to the TIFFRasterScanlineSize64() API. This flaw allows a remote attacker to cause a denial of service via a crafted input with a size smaller than 379 KB.", + "severity": "High", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-589394", + "references": [ + "https://gitlab.com/libtiff/libtiff/-/issues/621", + "https://security-tracker.debian.org/tracker/CVE-2023-52355", + "https://bugzilla.redhat.com/show_bug.cgi?id=2251326", + "https://access.redhat.com/security/cve/CVE-2023-52355" + ], + "extended_information": { + "short_description": "Unbounded resource consumption in libtiff may lead to denial of service when parsing a crafted tiff file.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "PoC is included in the git issue discussing the problem." + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS attack complexity does not reflect the contextual prerequisites required to exploit the vulnerability.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "To exploit the vulnerability, the attacker must be able to upload a tiff file whose size will get checked by the vulnerable `TIFFRasterScanlineSize64()` function, and allocate memory (without any limitations) based on the results.", + "is_positive": true + } + ], + "remediation": "##### Development mitigations\n\nAs a workaround, users could implement checks, or use `TIFFOpenOptionsSetMaxSingleMemAlloc()`, to reject files that they consider to consume too many resources for their use case. For example -\n```\n// Allow 1MB single mem alloc\nTIFFOpenOptionsSetMaxSingleMemAlloc(\u0026opts, 1*1024*1024);\n```" + } + }, + { + "cves": [ + { + "cve": "CVE-2023-25433", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-120" + ], + "cwe_details": { + "CWE-120": { + "name": "Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')", + "description": "The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow." + } + } + } + ], + "summary": "libtiff 4.5.0 is vulnerable to Buffer Overflow via /libtiff/tools/tiffcrop.c:8499. Incorrect updating of buffer size after rotateImage() in tiffcrop cause heap-buffer-overflow and SEGV.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-523034", + "references": [ + "https://gitlab.com/libtiff/libtiff/-/merge_requests/467", + "https://security-tracker.debian.org/tracker/CVE-2023-25433", + "https://gitlab.com/libtiff/libtiff/-/issues/520", + "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-6228", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "An issue was found in the tiffcp utility distributed by the libtiff package where a crafted TIFF file on processing may cause a heap-based buffer overflow leads to an application crash.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-539705", + "references": [ + "https://access.redhat.com/errata/RHSA-2024:5079", + "https://access.redhat.com/errata/RHSA-2024:2289", + "https://security-tracker.debian.org/tracker/CVE-2023-6228", + "https://access.redhat.com/security/cve/CVE-2023-6228", + "https://bugzilla.redhat.com/show_bug.cgi?id=2240995" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-52356", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "A segment fault (SEGV) flaw was found in libtiff that could be triggered by passing a crafted tiff file to the TIFFReadRGBATileExt() API. This flaw allows a remote attacker to cause a heap-buffer overflow, leading to a denial of service.", + "severity": "High", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-589395", + "references": [ + "https://access.redhat.com/errata/RHSA-2024:5079", + "https://support.apple.com/kb/HT214123", + "https://support.apple.com/kb/HT214118", + "http://seclists.org/fulldisclosure/2024/Jul/21", + "https://support.apple.com/kb/HT214122", + "https://support.apple.com/kb/HT214117", + "http://seclists.org/fulldisclosure/2024/Jul/20", + "http://seclists.org/fulldisclosure/2024/Jul/23", + "https://support.apple.com/kb/HT214116", + "http://seclists.org/fulldisclosure/2024/Jul/16", + "https://support.apple.com/kb/HT214119", + "https://support.apple.com/kb/HT214124", + "http://seclists.org/fulldisclosure/2024/Jul/17", + "https://support.apple.com/kb/HT214120", + "http://seclists.org/fulldisclosure/2024/Jul/19", + "http://seclists.org/fulldisclosure/2024/Jul/22", + "http://seclists.org/fulldisclosure/2024/Jul/18", + "https://lists.debian.org/debian-lts-announce/2024/03/msg00011.html", + "https://gitlab.com/libtiff/libtiff/-/issues/622", + "https://gitlab.com/libtiff/libtiff/-/merge_requests/546", + "https://security-tracker.debian.org/tracker/CVE-2023-52356", + "https://bugzilla.redhat.com/show_bug.cgi?id=2251344", + "https://access.redhat.com/security/cve/CVE-2023-52356" + ], + "extended_information": { + "short_description": "A heap buffer overflow in libtiff may lead to denial of service when parsing a crafted tiff image.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "To exploit the vulnerability, the attacker must be able to upload a maliciously crafted tiff image which will be parsed by the victim.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS score does not reflect the contextual prerequisites required to exploit the vulnerability.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-1916", + "cvss_v3_score": "6.1", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H", + "cwe": [ + "CWE-125" + ], + "cwe_details": { + "CWE-125": { + "name": "Out-of-bounds Read", + "description": "The product reads data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "7" + } + ] + } + } + } + ], + "summary": "A flaw was found in tiffcrop, a program distributed by the libtiff package. A specially crafted tiff file can lead to an out-of-bounds read in the extractImageSection function in tools/tiffcrop.c, resulting in a denial of service and limited information disclosure. This issue affects libtiff versions 4.x.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-513433", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-1916", + "https://gitlab.com/libtiff/libtiff/-/issues/536", + "https://gitlab.com/libtiff/libtiff/-/issues/537", + "https://gitlab.com/libtiff/libtiff/-/issues/536%2C", + "https://support.apple.com/kb/HT213844" + ] + }, + { + "cves": [ + { + "cve": "CVE-2017-9117", + "cvss_v2_score": "7.5", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-125" + ], + "cwe_details": { + "CWE-125": { + "name": "Out-of-bounds Read", + "description": "The product reads data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "7" + } + ] + } + } + } + ], + "summary": "In LibTIFF 4.0.7, the program processes BMP images without verifying that biWidth and biHeight in the bitmap-information header match the actual input, leading to a heap-based buffer over-read in bmp2tiff.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-54208", + "references": [ + "http://www.securityfocus.com/bid/98581", + "http://bugzilla.maptools.org/show_bug.cgi?id=2690", + "https://security-tracker.debian.org/tracker/CVE-2017-9117", + "https://usn.ubuntu.com/3606-1/" + ] + }, + { + "cves": [ + { + "cve": "CVE-2010-4665", + "cvss_v2_score": "4.3", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:N/A:P", + "cwe": [ + "CWE-189" + ] + } + ], + "summary": "Integer overflow in the ReadDirectory function in tiffdump.c in tiffdump in LibTIFF before 3.9.5 allows remote attackers to cause a denial of service (application crash) or possibly have unspecified other impact via a crafted TIFF file containing a directory data structure with many directory entries.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-36369", + "references": [ + "http://www.securityfocus.com/bid/47338", + "http://lists.fedoraproject.org/pipermail/package-announce/2011-April/058478.html", + "http://www.debian.org/security/2012/dsa-2552", + "http://lists.opensuse.org/opensuse-security-announce/2011-05/msg00005.html", + "https://security-tracker.debian.org/tracker/CVE-2010-4665", + "http://security.gentoo.org/glsa/glsa-201209-02.xml", + "http://secunia.com/advisories/44271", + "http://ubuntu.com/usn/usn-1416-1", + "http://bugzilla.maptools.org/show_bug.cgi?id=2218", + "https://bugzilla.redhat.com/show_bug.cgi?id=695887", + "http://www.remotesensing.org/libtiff/v3.9.5.html", + "http://secunia.com/advisories/50726", + "http://openwall.com/lists/oss-security/2011/04/12/10" + ] + }, + { + "cves": [ + { + "cve": "CVE-2022-1210", + "cvss_v2_score": "4.3", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:N/A:P", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-404" + ], + "cwe_details": { + "CWE-404": { + "name": "Improper Resource Shutdown or Release", + "description": "The product does not release or incorrectly releases a resource before it is made available for re-use." + } + } + } + ], + "summary": "A vulnerability classified as problematic was found in LibTIFF 4.3.0. Affected by this vulnerability is the TIFF File Handler of tiff2ps. Opening a malicious file leads to a denial of service. The attack can be launched remotely but requires user interaction. The exploit has been disclosed to the public and may be used.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-203004", + "references": [ + "https://vuldb.com/?id.196363", + "https://security.netapp.com/advisory/ntap-20220513-0005/", + "https://security-tracker.debian.org/tracker/CVE-2022-1210", + "https://security.gentoo.org/glsa/202210-10", + "https://gitlab.com/libtiff/libtiff/-/issues/402", + "https://gitlab.com/libtiff/libtiff/uploads/c3da94e53cf1e1e8e6d4d3780dc8c42f/example.tiff" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-3576", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-401" + ], + "cwe_details": { + "CWE-401": { + "name": "Missing Release of Memory after Effective Lifetime", + "description": "The product does not sufficiently track and release allocated memory after it has been used, which slowly consumes remaining memory." + } + } + } + ], + "summary": "A memory leak flaw was found in Libtiff's tiffcrop utility. This issue occurs when tiffcrop operates on a TIFF image file, allowing an attacker to pass a crafted TIFF image file to tiffcrop utility, which causes this memory leak issue, resulting an application crash, eventually leading to a denial of service.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-532917", + "references": [ + "https://access.redhat.com/security/cve/CVE-2023-3576", + "https://access.redhat.com/errata/RHSA-2023:6575", + "https://bugzilla.redhat.com/show_bug.cgi?id=2219340", + "https://lists.debian.org/debian-lts-announce/2024/03/msg00011.html", + "https://security-tracker.debian.org/tracker/CVE-2023-3576" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-3164", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "A heap-buffer-overflow vulnerability was found in LibTIFF, in extractImageSection() at tools/tiffcrop.c:7916 and tools/tiffcrop.c:7801. This flaw allows attackers to cause a denial of service via a crafted tiff file.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-521552", + "references": [ + "https://access.redhat.com/security/cve/CVE-2023-3164", + "https://security-tracker.debian.org/tracker/CVE-2023-3164", + "https://gitlab.com/libtiff/libtiff/-/issues/542", + "https://bugzilla.redhat.com/show_bug.cgi?id=2213531" + ], + "extended_information": { + "short_description": "A heap buffer overflow in the tiffcrop utility in libtiff possibly leads to remote code execution when parsing a crafted TIFF file.", + "full_description": "[libTIFF](http://www.simplesystems.org/libtiff/) is a popular library which provides support for the Tag Image File Format (TIFF), a widely used format for storing image data. One of the utilities that can be provided with libtiff is tiffcrop, which is most often used to extract portions of an image for processing.\n\n`tiffcrop` can be run with one or more flags. These flags include, but are not limited to:\n\n* `-S`: With the `-S` flag, `tiffcrop` will divide each image to equal columns and rows.\n* `-R`: With the `-R` flag, the provided TIFF image will be rotated.\n* `-e`: With the `-e` flag, the user can specify the export mode for images and selections from input images.\n\nWhen running `tiffcrop` with the `-e` flag set to `divided`, `multiple` or `separate`, with the `-S` flag and also with the `-R` flag, an attacker can provide a crafted TIFF file which will cause a heap overflow in the `processCropSelections()` function.\n\nAlthough the heap overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "For an attacker to exploit this vulnerability, `tiffcrop` has to be invoked with specific `-e`, '-S' and `-R` flags. In addition to this, the attacker has to be able to supply a crafted TIFF file as input.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "The vulnerability may lead to remote code execution." + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Although heap overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "A crafted TIFF file is publicly available that demonstrates crashing `libtiff`." + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2018-10126", + "cvss_v2_score": "4.3", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:N/A:P", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-476" + ], + "cwe_details": { + "CWE-476": { + "name": "NULL Pointer Dereference", + "description": "A NULL pointer dereference occurs when the application dereferences a pointer that it expects to be valid, but is NULL, typically causing a crash or exit.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "12" + } + ] + } + } + } + ], + "summary": "ijg-libjpeg before 9d, as used in tiff2pdf (from LibTIFF) and other products, does not check for a NULL pointer at a certain place in jpeg_fdct_16x16 in jfdctint.c.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-67637", + "references": [ + "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772%40%3Cdev.mina.apache.org%3E", + "https://security-tracker.debian.org/tracker/CVE-2018-10126", + "https://gitlab.com/libtiff/libtiff/-/issues/128", + "http://bugzilla.maptools.org/show_bug.cgi?id=2786" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-41175", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-190" + ], + "cwe_details": { + "CWE-190": { + "name": "Integer Overflow or Wraparound", + "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "14" + } + ] + } + } + } + ], + "summary": "A vulnerability was found in libtiff due to multiple potential integer overflows in raw2tiff.c. This flaw allows remote attackers to cause a denial of service or possibly execute an arbitrary code via a crafted tiff image, which triggers a heap-based buffer overflow.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-529113", + "references": [ + "https://bugzilla.redhat.com/show_bug.cgi?id=2235264", + "https://access.redhat.com/errata/RHSA-2024:2289", + "https://security-tracker.debian.org/tracker/CVE-2023-41175", + "https://access.redhat.com/security/cve/CVE-2023-41175" + ], + "extended_information": { + "short_description": "An integer overflow in libtiff's raw2tiff may lead to remote code execution when parsing crafted images.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "For an attacker to exploit this vulnerability, `raw2tiff` has to be invoked with the `-l`, `-b` and `-w` flags. In addition to this, the attacker has to be able to supply a crafted TIFF file as input.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "PoC was published along with the git issue." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "The vulnerability leads to denial of service and possibly remote code execution." + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Although integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2017-5563", + "cvss_v2_score": "6.8", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:P/I:P/A:P", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-125" + ], + "cwe_details": { + "CWE-125": { + "name": "Out-of-bounds Read", + "description": "The product reads data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "7" + } + ] + } + } + } + ], + "summary": "LibTIFF version 4.0.7 is vulnerable to a heap-based buffer over-read in tif_lzw.c resulting in DoS or code execution via a crafted bmp image to tools/bmp2tiff.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-46608", + "references": [ + "https://security.gentoo.org/glsa/201709-27", + "http://bugzilla.maptools.org/show_bug.cgi?id=2664", + "https://usn.ubuntu.com/3606-1/", + "http://www.securityfocus.com/bid/95705", + "https://security-tracker.debian.org/tracker/CVE-2017-5563" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-7006", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-476" + ], + "cwe_details": { + "CWE-476": { + "name": "NULL Pointer Dereference", + "description": "A NULL pointer dereference occurs when the application dereferences a pointer that it expects to be valid, but is NULL, typically causing a crash or exit.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "12" + } + ] + } + } + } + ], + "summary": "A null pointer dereference flaw was found in Libtiff via `tif_dirinfo.c`. This issue may allow an attacker to trigger memory allocation failures through certain means, such as restricting the heap space size or injecting faults, causing a segmentation fault. This can cause an application crash, eventually leading to a denial of service.", + "severity": "High", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-617888", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-7006", + "https://access.redhat.com/security/cve/CVE-2024-7006", + "https://bugzilla.redhat.com/show_bug.cgi?id=2302996", + "https://access.redhat.com/errata/RHSA-2024:6360" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-40745", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-190" + ], + "cwe_details": { + "CWE-190": { + "name": "Integer Overflow or Wraparound", + "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "14" + } + ] + } + } + } + ], + "summary": "LibTIFF is vulnerable to an integer overflow. This flaw allows remote attackers to cause a denial of service (application crash) or possibly execute an arbitrary code via a crafted tiff image, which triggers a heap-based buffer overflow.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libtiff6:4.5.0-6": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", + "full_path": "libtiff6:4.5.0-6" + } + ] + ] + } + }, + "issue_id": "XRAY-529112", + "references": [ + "https://access.redhat.com/security/cve/CVE-2023-40745", + "https://access.redhat.com/errata/RHSA-2024:2289", + "https://security-tracker.debian.org/tracker/CVE-2023-40745", + "https://security.netapp.com/advisory/ntap-20231110-0005/", + "https://bugzilla.redhat.com/show_bug.cgi?id=2235265" + ], + "extended_information": { + "short_description": "An integer overflow in libtiff’s tiffcp may lead to remote code execution when parsing crafted images.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "For an attacker to exploit this vulnerability, `tiffcp` has to be invoked with the `-m` flag with an attacker-controlled value. In addition to this, the attacker has to be able to supply a crafted TIFF file as input.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "A PoC which demonstrates denial of service was published along with the git issue." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "The vulnerability leads to denial of service and possibly remote code execution." + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Although integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-2953", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-476" + ], + "cwe_details": { + "CWE-476": { + "name": "NULL Pointer Dereference", + "description": "A NULL pointer dereference occurs when the application dereferences a pointer that it expects to be valid, but is NULL, typically causing a crash or exit.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "12" + } + ] + } + } + } + ], + "summary": "A vulnerability was found in openldap. This security flaw causes a null pointer dereference in ber_memalloc_x() function.", + "severity": "High", + "components": { + "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5", + "full_path": "libldap-2.5-0:2.5.13+dfsg-5" + } + ] + ] + } + }, + "issue_id": "XRAY-520865", + "references": [ + "http://seclists.org/fulldisclosure/2023/Jul/48", + "https://support.apple.com/kb/HT213845", + "http://seclists.org/fulldisclosure/2023/Jul/47", + "https://bugs.openldap.org/show_bug.cgi?id=9904", + "https://security-tracker.debian.org/tracker/CVE-2023-2953", + "https://support.apple.com/kb/HT213844", + "https://access.redhat.com/security/cve/CVE-2023-2953", + "https://security.netapp.com/advisory/ntap-20230703-0005/", + "http://seclists.org/fulldisclosure/2023/Jul/52", + "https://support.apple.com/kb/HT213843" + ] + }, + { + "cves": [ + { + "cve": "CVE-2020-15719", + "cvss_v2_score": "4.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:H/Au:N/C:P/I:P/A:N", + "cvss_v3_score": "4.2", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N", + "cwe": [ + "CWE-295" + ], + "cwe_details": { + "CWE-295": { + "name": "Improper Certificate Validation", + "description": "The product does not validate, or incorrectly validates, a certificate." + } + } + } + ], + "summary": "libldap in certain third-party OpenLDAP packages has a certificate-validation flaw when the third-party package is asserting RFC6125 support. It considers CN even when there is a non-matching subjectAltName (SAN). This is fixed in, for example, openldap-2.4.46-10.el8 in Red Hat Enterprise Linux.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5", + "full_path": "libldap-2.5-0:2.5.13+dfsg-5" + } + ] + ] + } + }, + "issue_id": "XRAY-113528", + "references": [ + "https://kc.mcafee.com/corporate/index?page=content\u0026id=SB10365", + "https://www.oracle.com/security-alerts/cpuapr2022.html", + "http://lists.opensuse.org/opensuse-security-announce/2020-09/msg00033.html", + "https://security-tracker.debian.org/tracker/CVE-2020-15719", + "http://lists.opensuse.org/opensuse-security-announce/2020-09/msg00059.html", + "https://bugzilla.redhat.com/show_bug.cgi?id=1740070", + "https://bugs.openldap.org/show_bug.cgi?id=9266", + "https://access.redhat.com/errata/RHBA-2019:3674" + ] + }, + { + "cves": [ + { + "cve": "CVE-2017-14159", + "cvss_v2_score": "1.9", + "cvss_v2_vector": "CVSS:2.0/AV:L/AC:M/Au:N/C:N/I:N/A:P", + "cvss_v3_score": "4.7", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-665" + ], + "cwe_details": { + "CWE-665": { + "name": "Improper Initialization", + "description": "The product does not initialize or incorrectly initializes a resource, which might leave the resource in an unexpected state when it is accessed or used." + } + } + } + ], + "summary": "slapd in OpenLDAP 2.4.45 and earlier creates a PID file after dropping privileges to a non-root account, which might allow local users to kill arbitrary processes by leveraging access to this non-root account for PID file modification before a root script executes a \"kill `cat /pathname`\" command, as demonstrated by openldap-initscript.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5", + "full_path": "libldap-2.5-0:2.5.13+dfsg-5" + } + ] + ] + } + }, + "issue_id": "XRAY-58392", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2017-14159", + "http://www.openldap.org/its/index.cgi?findid=8703", + "https://www.oracle.com/security-alerts/cpuapr2022.html" + ] + }, + { + "cves": [ + { + "cve": "CVE-2015-3276", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:P/A:N", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", + "cwe": [ + "NVD-CWE-noinfo" + ] + } + ], + "summary": "The nss_parse_ciphers function in libraries/libldap/tls_m.c in OpenLDAP does not properly parse OpenSSL-style multi-keyword mode cipher strings, which might cause a weaker than intended cipher to be used and allow remote attackers to have unspecified impact via unknown vectors.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5", + "full_path": "libldap-2.5-0:2.5.13+dfsg-5" + } + ] + ] + } + }, + "issue_id": "XRAY-37126", + "references": [ + "http://rhn.redhat.com/errata/RHSA-2015-2131.html", + "http://www.securitytracker.com/id/1034221", + "https://security-tracker.debian.org/tracker/CVE-2015-3276", + "http://www.oracle.com/technetwork/topics/security/linuxbulletinoct2015-2719645.html", + "https://bugzilla.redhat.com/show_bug.cgi?id=1238322" + ] + }, + { + "cves": [ + { + "cve": "CVE-2017-17740", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-119" + ], + "cwe_details": { + "CWE-119": { + "name": "Improper Restriction of Operations within the Bounds of a Memory Buffer", + "description": "The product performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "17" + } + ] + } + } + } + ], + "summary": "contrib/slapd-modules/nops/nops.c in OpenLDAP through 2.4.45, when both the nops module and the memberof overlay are enabled, attempts to free a buffer that was allocated on the stack, which allows remote attackers to cause a denial of service (slapd crash) via a member MODDN operation.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5", + "full_path": "libldap-2.5-0:2.5.13+dfsg-5" + } + ] + ] + } + }, + "issue_id": "XRAY-60510", + "references": [ + "http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00053.html", + "https://security-tracker.debian.org/tracker/CVE-2017-17740", + "http://www.openldap.org/its/index.cgi/Incoming?id=8759", + "https://kc.mcafee.com/corporate/index?page=content\u0026id=SB10365", + "http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00058.html", + "https://www.oracle.com/security-alerts/cpuapr2022.html" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-22365", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "NVD-CWE-noinfo" + ] + } + ], + "summary": "linux-pam (aka Linux PAM) before 1.6.0 allows attackers to cause a denial of service (blocked login process) via mkfifo because the openat call (for protect_dir) lacks O_DIRECTORY.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libpam-modules-bin:1.5.2-6+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libpam-modules-bin:1.5.2-6+deb12u1", + "full_path": "libpam-modules-bin:1.5.2-6+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libpam-modules:1.5.2-6+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libpam-modules:1.5.2-6+deb12u1", + "full_path": "libpam-modules:1.5.2-6+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libpam-runtime:1.5.2-6+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libpam-runtime:1.5.2-6+deb12u1", + "full_path": "libpam-runtime:1.5.2-6+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libpam0g:1.5.2-6+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libpam0g:1.5.2-6+deb12u1", + "full_path": "libpam0g:1.5.2-6+deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-588807", + "references": [ + "https://github.com/linux-pam/linux-pam", + "http://www.openwall.com/lists/oss-security/2024/01/18/3", + "https://github.com/linux-pam/linux-pam/commit/031bb5a5d0d950253b68138b498dc93be69a64cb", + "https://github.com/linux-pam/linux-pam/releases/tag/v1.6.0", + "https://security-tracker.debian.org/tracker/CVE-2024-22365" + ] + }, + { + "cves": [ + { + "cve": "CVE-2015-9019", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:N/A:N", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", + "cwe": [ + "CWE-330" + ], + "cwe_details": { + "CWE-330": { + "name": "Use of Insufficiently Random Values", + "description": "The product uses insufficiently random numbers or values in a security context that depends on unpredictable numbers." + } + } + } + ], + "summary": "In libxslt 1.1.29 and earlier, the EXSLT math.random function was not initialized with a random seed during startup, which could cause usage of this function to produce predictable outputs.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libxslt1.1:1.1.35-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libxslt1.1:1.1.35-1", + "full_path": "libxslt1.1:1.1.35-1" + } + ] + ] + } + }, + "issue_id": "XRAY-52917", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2015-9019", + "https://bugzilla.gnome.org/show_bug.cgi?id=758400", + "https://bugzilla.suse.com/show_bug.cgi?id=934119" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-5171", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-190" + ], + "cwe_details": { + "CWE-190": { + "name": "Integer Overflow or Wraparound", + "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "14" + } + ] + } + } + } + ], + "summary": "Integer overflow in libaom internal function img_alloc_helper can lead to heap buffer overflow. This function can be reached via 3 callers:\n\n\n * Calling aom_img_alloc() with a large value of the d_w, d_h, or align parameter may result in integer overflows in the calculations of buffer sizes and offsets and some fields of the returned aom_image_t struct may be invalid.\n * Calling aom_img_wrap() with a large value of the d_w, d_h, or align parameter may result in integer overflows in the calculations of buffer sizes and offsets and some fields of the returned aom_image_t struct may be invalid.\n * Calling aom_img_alloc_with_border() with a large value of the d_w, d_h, align, size_align, or border parameter may result in integer overflows in the calculations of buffer sizes and offsets and some fields of the returned aom_image_t struct may be invalid.", + "severity": "Critical", + "components": { + "deb://debian:bookworm:libaom3:3.6.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libaom3:3.6.0-1", + "full_path": "libaom3:3.6.0-1" + } + ] + ] + } + }, + "issue_id": "XRAY-604193", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-5171", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/6HYUEHZ35ZPY2EONVZCGO6LPT3AMLZCP/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/U5NRNCEYS246CYGOR32MF7OGKWOWER22/", + "https://issues.chromium.org/issues/332382766" + ], + "extended_information": { + "short_description": "An integer overflow in libaom may lead to remote code execution when parsing malicious video data.", + "full_description": "[Libaom](https://aomedia.googlesource.com/aom/) is the reference encoder and decoder library for the `AV1` video codec. AV1 (AOMedia Video 1) is an open, royalty-free video coding format designed for video transmissions over the Internet. It was developed by the Alliance for Open Media (AOMedia), a consortium that includes firms like Google, Cisco, Microsoft, Mozilla, and Netflix.\nThe `aom` in libaom stands for `Alliance for Open Media`, and the library serves as a standard reference codebase that can be used to implement AV1 compression and decompression.\n\nProviding large values as the arguments to the `img_alloc_helper()` function, may lead to an integer overflow and a subsequent heap buffer overflow, which may lead to remote code execution.\n\n`img_alloc_helper()` function is an internal function that is used to allocate memory for an `aom_image_t` structure and its associated image data. This function is very useful when you need to manually create an image buffer that can then be used with the AOM codec for various operations like encoding or decoding.\n\nThe vulnerability cannot be exploited directly by calling `img_alloc_helper()` because it is an internal function. \n\nAlthough integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.\n\nTo exploit this vulnerability the following functions can be called with excessively large values as parameters:\n\n* `aom_img_alloc()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_wrap()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_alloc_with_border()` with a large value of the d_w, d_h, align, size_align, or border parameters.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "The published exploit demonstrates DoS." + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Although integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "The highest potential impact of this issue is severe (Remote Code Execution). Although no such impact has been demonstrated in practice." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker would need to find input propagating into the libaom encoding or decoding operations.", + "is_positive": true + } + ], + "remediation": "##### Development mitigations\n\nMake sure the following functions don't accept excessively large values as arguments to the following functions:\n\n* `aom_img_alloc()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_wrap()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_alloc_with_border()` with a large value of the d_w, d_h, align, size_align, or border parameters." + } + }, + { + "cves": [ + { + "cve": "CVE-2023-39616", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-119" + ], + "cwe_details": { + "CWE-119": { + "name": "Improper Restriction of Operations within the Bounds of a Memory Buffer", + "description": "The product performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "17" + } + ] + } + } + } + ], + "summary": "AOMedia v3.0.0 to v3.5.0 was discovered to contain an invalid read memory access via the component assign_frame_buffer_p in av1/common/av1_common_int.h.", + "severity": "High", + "components": { + "deb://debian:bookworm:libaom3:3.6.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libaom3:3.6.0-1", + "full_path": "libaom3:3.6.0-1" + } + ] + ] + } + }, + "issue_id": "XRAY-529506", + "references": [ + "https://bugs.chromium.org/p/aomedia/issues/detail?id=3372#c3", + "https://security-tracker.debian.org/tracker/CVE-2023-39616" + ], + "extended_information": { + "short_description": "Invalid pointer dereference in libaom leads to denial of service when encoding crafted video data with nondefault configuration options set.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "The published exploit demonstrates DoS" + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The issue can be exploited by the `aomenc` CLI tool when called on arbitrary input file with the flag `--drop-frame=1` - \n`aomenc --passes=1 -h 1 -w 1 --drop-frame=1 --end-usage=cbr --buf-sz=1 -o /dev/null poc`\n \n\nAlternatively, the issue can be exploited through `libaom` when calling `aom_codec_enc_init` where the 3rd arg (`config`) has `dropframe_thresh == 1` + calling `aom_codec_encode` with external input to the 2nd arg (`img`)", + "is_positive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Exploiting the DoS via invocation of the `aomenc` CLI tool has minimal security impact, since exploitation will cause the `aomenc` forked utiliy process to crash (crashing a forked process has minimal security impact)\n\nThe issue can also be exploited via specific calls to `libaom`, however the configuration needed is extremely rare and crashing a video encoder usually does not have a high security impact.\n\nDebian classified this CVE as a \"minor issue\"", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-6879", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "Increasing the resolution of video frames, while performing a multi-threaded encode, can result in a heap overflow in av1_loop_restoration_dealloc().", + "severity": "Critical", + "components": { + "deb://debian:bookworm:libaom3:3.6.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libaom3:3.6.0-1", + "full_path": "libaom3:3.6.0-1" + } + ] + ] + } + }, + "issue_id": "XRAY-585747", + "references": [ + "https://aomedia.googlesource.com/aom/+/refs/tags/v3.7.1", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D6C2HN4T2S6GYNTAUXLH45LQZHK7QPHP/", + "https://crbug.com/aomedia/3491", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/AYONA2XSNFMXLAW4IHLFI5UVV3QRNG5K/", + "https://security-tracker.debian.org/tracker/CVE-2023-6879" + ], + "extended_information": { + "short_description": "Heap buffer overread in the av1 module of the aom library can lead to denial of service when resizing frames under special conditions.", + "full_description": "AOM (Alliance for Open Media) is an open-source, royalty-free video codec library implemented in C, developed by the Alliance for Open Media, a consortium of technology companies and research institutions. The AOM library supports the AV1, VP9, and Thor video formats, providing high-quality video compression and is used for a variety of applications, including video streaming, video conferencing, and video editing.\nThe AV1 codec, developed by the Alliance for Open Media, is a state-of-the-art video compression technology that achieves exceptional efficiency while preserving high visual quality. The AOM library provides a comprehensive toolkit for working with AV1-encoded video streams, offering encoding, decoding, and manipulation capabilities.\n\nA vulnerability was found when using the `aom_codec_destroy()` function to clean up memory after resizing AV1 frames, specifically when:\n\n- Using AV1 codec (`aom_codec_av1_cx()`)\n- Utilizing multiple threads\n```\naom_codec_enc_cfg_t cfg;\naom_codec_enc_config_default(iface, \u0026cfg, AOM_USAGE_GOOD_QUALITY));\ncfg.g_threads = 4;\n```\n\nUnder these conditions, a Denial of Service (DoS) vulnerability emerges, manifesting as a heap buffer overread during object destruction.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "A public example of vulnerable AOM code exists, which shows how a DoS might be triggered." + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Under normal circumstances, the attacker cannot supply input which will trigger this vulnerability (either the vulnerable code exists or does not exist).", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The vulnerability triggers under the following conditions -\n- use of the AV1 codec (`aom_codec_av1_cx()`)\n- use of more than 1 thread:\n```\naom_codec_enc_cfg_t cfg;\naom_codec_enc_config_default(iface, \u0026cfg, AOM_USAGE_GOOD_QUALITY));\ncfg.g_threads = 4;\n```\n- cleaning the memory at the end of the encoding process (`aom_codec_destroy()`)", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2024-28757" + } + ], + "summary": "libexpat through 2.6.1 allows an XML Entity Expansion attack when there is isolated use of external parsers (created via XML_ExternalEntityParserCreate).", + "severity": "Low", + "components": { + "deb://debian:bookworm:libexpat1:2.5.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", + "full_path": "libexpat1:2.5.0-1" + } + ] + ] + } + }, + "issue_id": "XRAY-593447", + "references": [ + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LKJ7V5F6LJCEQJXDBWGT27J7NAP3E3N7/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/VK2O34GH43NTHBZBN7G5Y6YKJKPUCTBE/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/FPLC6WDSRDUYS7F7JWAOVOHFNOUQ43DD/", + "http://www.openwall.com/lists/oss-security/2024/03/15/1", + "https://github.com/libexpat/libexpat/issues/839", + "https://github.com/libexpat/libexpat/pull/842", + "https://security.netapp.com/advisory/ntap-20240322-0001/", + "https://security-tracker.debian.org/tracker/CVE-2024-28757" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-45492", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-190" + ], + "cwe_details": { + "CWE-190": { + "name": "Integer Overflow or Wraparound", + "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "14" + } + ] + } + } + } + ], + "summary": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", + "severity": "Critical", + "components": { + "deb://debian:bookworm:libexpat1:2.5.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", + "full_path": "libexpat1:2.5.0-1" + } + ] + ] + } + }, + "issue_id": "XRAY-632612", + "references": [ + "https://github.com/libexpat/libexpat/issues/889", + "https://security-tracker.debian.org/tracker/CVE-2024-45492", + "https://github.com/libexpat/libexpat/pull/892" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-52426", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-776" + ], + "cwe_details": { + "CWE-776": { + "name": "Improper Restriction of Recursive Entity References in DTDs ('XML Entity Expansion')", + "description": "The product uses XML documents and allows their structure to be defined with a Document Type Definition (DTD), but it does not properly control the number of recursive definitions of entities." + } + } + } + ], + "summary": "libexpat through 2.5.0 allows recursive XML Entity Expansion if XML_DTD is undefined at compile time.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libexpat1:2.5.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", + "full_path": "libexpat1:2.5.0-1" + } + ] + ] + } + }, + "issue_id": "XRAY-589896", + "references": [ + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/PNRIHC7DVVRAIWFRGV23Y6UZXFBXSQDB/", + "https://security-tracker.debian.org/tracker/CVE-2023-52426", + "https://cwe.mitre.org/data/definitions/776.html", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/WNUBSGZFEZOBHJFTAD42SAN4ATW2VEMV/", + "https://security.netapp.com/advisory/ntap-20240307-0005/", + "https://github.com/libexpat/libexpat/commit/0f075ec8ecb5e43f8fdca5182f8cca4703da0404", + "https://github.com/libexpat/libexpat/pull/777" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-45491", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-190" + ], + "cwe_details": { + "CWE-190": { + "name": "Integer Overflow or Wraparound", + "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "14" + } + ] + } + } + } + ], + "summary": "An issue was discovered in libexpat before 2.6.3. dtdCopy in xmlparse.c can have an integer overflow for nDefaultAtts on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", + "severity": "Critical", + "components": { + "deb://debian:bookworm:libexpat1:2.5.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", + "full_path": "libexpat1:2.5.0-1" + } + ] + ] + } + }, + "issue_id": "XRAY-632611", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-45491", + "https://github.com/libexpat/libexpat/pull/891", + "https://github.com/libexpat/libexpat/issues/888" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-45490", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-611" + ], + "cwe_details": { + "CWE-611": { + "name": "Improper Restriction of XML External Entity Reference", + "description": "The product processes an XML document that can contain XML entities with URIs that resolve to documents outside of the intended sphere of control, causing the product to embed incorrect documents into its output." + } + } + } + ], + "summary": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", + "severity": "Critical", + "components": { + "deb://debian:bookworm:libexpat1:2.5.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", + "full_path": "libexpat1:2.5.0-1" + } + ] + ] + } + }, + "issue_id": "XRAY-632613", + "references": [ + "https://github.com/libexpat/libexpat/issues/887", + "https://security-tracker.debian.org/tracker/CVE-2024-45490", + "https://github.com/libexpat/libexpat/pull/890" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-52425", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-400" + ], + "cwe_details": { + "CWE-400": { + "name": "Uncontrolled Resource Consumption", + "description": "The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources." + } + } + } + ], + "summary": "libexpat through 2.5.0 allows a denial of service (resource consumption) because many full reparsings are required in the case of a large token for which multiple buffer fills are needed.", + "severity": "High", + "components": { + "deb://debian:bookworm:libexpat1:2.5.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", + "full_path": "libexpat1:2.5.0-1" + } + ] + ] + } + }, + "issue_id": "XRAY-589898", + "references": [ + "http://www.openwall.com/lists/oss-security/2024/03/20/5", + "https://security.netapp.com/advisory/ntap-20240614-0003/", + "https://github.com/libexpat/libexpat/pull/789", + "https://lists.debian.org/debian-lts-announce/2024/04/msg00006.html", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/PNRIHC7DVVRAIWFRGV23Y6UZXFBXSQDB/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/WNUBSGZFEZOBHJFTAD42SAN4ATW2VEMV/", + "https://security-tracker.debian.org/tracker/CVE-2023-52425" + ], + "extended_information": { + "short_description": "A design problem in libexpat may lead to denial of service when parsing a crafted XML document with large tokens.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "A PoC demonstrating denial-of-service can be found in Expat's tests." + }, + { + "name": "The issue is trivial to exploit and does not require a published writeup or PoC", + "description": "The issue doesn't require any in-depth knowledge to trigger as a proof-of-concept exists in the official fix commit." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Exploitation of the vulnerability leads to high resource consumption which may lead to denial of service." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "Exploitation requires passing user-controlled input to an XML parsing function such as `XML_Parse`.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2013-0337", + "cvss_v2_score": "7.5", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P", + "cwe": [ + "CWE-264" + ] + } + ], + "summary": "The default configuration of nginx, possibly 1.3.13 and earlier, uses world-readable permissions for the (1) access.log and (2) error.log files, which allows local users to obtain sensitive information by reading the files.", + "severity": "Low", + "components": { + "deb://debian:bookworm:nginx:1.25.2-1~bookworm": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:nginx:1.25.2-1~bookworm", + "full_path": "nginx:1.25.2-1~bookworm" + } + ] + ] + } + }, + "issue_id": "XRAY-32935", + "references": [ + "http://security.gentoo.org/glsa/glsa-201310-04.xml", + "http://www.openwall.com/lists/oss-security/2013/02/24/1", + "http://secunia.com/advisories/55181", + "http://www.openwall.com/lists/oss-security/2013/02/22/1", + "https://security-tracker.debian.org/tracker/CVE-2013-0337", + "http://www.openwall.com/lists/oss-security/2013/02/21/15" + ] + }, + { + "cves": [ + { + "cve": "CVE-2009-4487", + "cvss_v2_score": "6.8", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:P/I:P/A:P", + "cwe": [ + "NVD-CWE-noinfo" + ] + } + ], + "summary": "nginx 0.7.64 writes data to a log file without sanitizing non-printable characters, which might allow remote attackers to modify a window's title, or possibly execute arbitrary commands or overwrite files, via an HTTP request containing an escape sequence for a terminal emulator.", + "severity": "Low", + "components": { + "deb://debian:bookworm:nginx:1.25.2-1~bookworm": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:nginx:1.25.2-1~bookworm", + "full_path": "nginx:1.25.2-1~bookworm" + } + ] + ] + } + }, + "issue_id": "XRAY-34279", + "references": [ + "http://www.securityfocus.com/bid/37711", + "http://www.ush.it/team/ush/hack_httpd_escape/adv.txt", + "https://security-tracker.debian.org/tracker/CVE-2009-4487", + "http://www.securityfocus.com/archive/1/508830/100/0/threaded" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-7347", + "cvss_v3_score": "4.7", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-125" + ], + "cwe_details": { + "CWE-125": { + "name": "Out-of-bounds Read", + "description": "The product reads data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "7" + } + ] + } + } + } + ], + "summary": "NGINX Open Source and NGINX Plus have a vulnerability in the ngx_http_mp4_module, which might allow an attacker to over-read NGINX worker memory resulting in its termination, using a specially crafted mp4 file. The issue only affects NGINX if it is built with the ngx_http_mp4_module and the mp4 directive is used in the configuration file. Additionally, the attack is possible only if an attacker can trigger the processing of a specially crafted mp4 file with the ngx_http_mp4_module.  Note: Software versions which have reached End of Technical Support (EoTS) are not evaluated.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:nginx:1.25.2-1~bookworm": { + "fixed_versions": [ + "[1.26.0-2]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:nginx:1.25.2-1~bookworm", + "full_path": "nginx:1.25.2-1~bookworm" + } + ] + ] + } + }, + "issue_id": "XRAY-619023", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-7347", + "https://my.f5.com/manage/s/article/K000140529" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-1580" + } + ], + "summary": "An integer overflow in dav1d AV1 decoder that can occur when decoding videos with large frame size. This can lead to memory corruption within the AV1 decoder. We recommend upgrading past version 1.4.0 of dav1d.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libdav1d6:1.0.0-2": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libdav1d6:1.0.0-2", + "full_path": "libdav1d6:1.0.0-2" + } + ] + ] + } + }, + "issue_id": "XRAY-590844", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-1580", + "http://seclists.org/fulldisclosure/2024/Mar/38", + "https://support.apple.com/kb/HT214093", + "https://code.videolan.org/videolan/dav1d/-/releases/1.4.0", + "http://seclists.org/fulldisclosure/2024/Mar/41", + "http://seclists.org/fulldisclosure/2024/Mar/39", + "https://support.apple.com/kb/HT214098", + "http://seclists.org/fulldisclosure/2024/Mar/40", + "http://seclists.org/fulldisclosure/2024/Mar/36", + "https://support.apple.com/kb/HT214096", + "https://support.apple.com/kb/HT214095", + "http://seclists.org/fulldisclosure/2024/Mar/37", + "https://support.apple.com/kb/HT214097", + "https://support.apple.com/kb/HT214094", + "https://code.videolan.org/videolan/dav1d/-/blob/master/NEWS", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/5EPMUNDMEBGESOJ2ZNCWYEAYOOEKNWOO/" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-32570", + "cvss_v3_score": "5.9", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-362" + ], + "cwe_details": { + "CWE-362": { + "name": "Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')", + "description": "The product contains a code sequence that can run concurrently with other code, and the code sequence requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence that is operating concurrently.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "21" + } + ] + } + } + } + ], + "summary": "VideoLAN dav1d before 1.2.0 has a thread_task.c race condition that can lead to an application crash, related to dav1d_decode_frame_exit.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libdav1d6:1.0.0-2": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libdav1d6:1.0.0-2", + "full_path": "libdav1d6:1.0.0-2" + } + ] + ] + } + }, + "issue_id": "XRAY-519404", + "references": [ + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/3WGSO7UMOF4MVLQ5H6KIV7OG6ONS377B/", + "https://security-tracker.debian.org/tracker/CVE-2023-32570", + "https://code.videolan.org/videolan/dav1d/-/tags/1.2.0", + "https://code.videolan.org/videolan/dav1d/-/commit/cf617fdae0b9bfabd27282854c8e81450d955efa", + "https://security.gentoo.org/glsa/202310-05", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LXZ6CUNJFDJLCFOZHY2TIGMCAEITLCRP/" + ] + }, + { + "cves": [ + { + "cve": "CVE-2016-2781", + "cvss_v2_score": "2.1", + "cvss_v2_vector": "CVSS:2.0/AV:L/AC:L/Au:N/C:N/I:P/A:N", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N", + "cwe": [ + "CWE-20" + ], + "cwe_details": { + "CWE-20": { + "name": "Improper Input Validation", + "description": "The product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "6" + } + ] + } + } + } + ], + "summary": "chroot in GNU coreutils, when used with --userspec, allows local users to escape to the parent session via a crafted TIOCSTI ioctl call, which pushes characters to the terminal's input buffer.", + "severity": "Low", + "components": { + "deb://debian:bookworm:coreutils:9.1-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:coreutils:9.1-1", + "full_path": "coreutils:9.1-1" + } + ] + ] + } + }, + "issue_id": "XRAY-28549", + "references": [ + "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772%40%3Cdev.mina.apache.org%3E", + "https://security-tracker.debian.org/tracker/CVE-2016-2781", + "http://www.openwall.com/lists/oss-security/2016/02/28/2", + "http://www.openwall.com/lists/oss-security/2016/02/28/3" + ] + }, + { + "cves": [ + { + "cve": "CVE-2017-18018", + "cvss_v2_score": "1.9", + "cvss_v2_vector": "CVSS:2.0/AV:L/AC:M/Au:N/C:N/I:P/A:N", + "cvss_v3_score": "4.7", + "cvss_v3_vector": "CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:N", + "cwe": [ + "CWE-362" + ], + "cwe_details": { + "CWE-362": { + "name": "Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')", + "description": "The product contains a code sequence that can run concurrently with other code, and the code sequence requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence that is operating concurrently.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "21" + } + ] + } + } + } + ], + "summary": "In GNU Coreutils through 8.29, chown-core.c in chown and chgrp does not prevent replacement of a plain file with a symlink during use of the POSIX \"-R -L\" options, which allows local users to modify the ownership of arbitrary files by leveraging a race condition.", + "severity": "Low", + "components": { + "deb://debian:bookworm:coreutils:9.1-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:coreutils:9.1-1", + "full_path": "coreutils:9.1-1" + } + ] + ] + } + }, + "issue_id": "XRAY-60415", + "references": [ + "http://lists.gnu.org/archive/html/coreutils/2017-12/msg00045.html", + "https://security-tracker.debian.org/tracker/CVE-2017-18018" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-28085" + } + ], + "summary": "wall in util-linux through 2.40, often installed with setgid tty permissions, allows escape sequences to be sent to other users' terminals through argv. (Specifically, escape sequences received from stdin are blocked, but escape sequences received from argv are not blocked.) There may be plausible scenarios where this leads to account takeover.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:bsdutils:1:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:bsdutils:1:2.38.1-5+b1", + "full_path": "bsdutils:1:2.38.1-5+b1" + } + ] + ] + }, + "deb://debian:bookworm:libblkid1:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libblkid1:2.38.1-5+b1", + "full_path": "libblkid1:2.38.1-5+b1" + } + ] + ] + }, + "deb://debian:bookworm:libmount1:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libmount1:2.38.1-5+b1", + "full_path": "libmount1:2.38.1-5+b1" + } + ] + ] + }, + "deb://debian:bookworm:libsmartcols1:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libsmartcols1:2.38.1-5+b1", + "full_path": "libsmartcols1:2.38.1-5+b1" + } + ] + ] + }, + "deb://debian:bookworm:libuuid1:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libuuid1:2.38.1-5+b1", + "full_path": "libuuid1:2.38.1-5+b1" + } + ] + ] + }, + "deb://debian:bookworm:mount:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:mount:2.38.1-5+b1", + "full_path": "mount:2.38.1-5+b1" + } + ] + ] + }, + "deb://debian:bookworm:util-linux-extra:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:util-linux-extra:2.38.1-5+b1", + "full_path": "util-linux-extra:2.38.1-5+b1" + } + ] + ] + }, + "deb://debian:bookworm:util-linux:2.38.1-5+b1": { + "fixed_versions": [ + "[2.38.1-5+deb12u1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:util-linux:2.38.1-5+b1", + "full_path": "util-linux:2.38.1-5+b1" + } + ] + ] + } + }, + "issue_id": "XRAY-596193", + "references": [ + "http://www.openwall.com/lists/oss-security/2024/03/27/8", + "http://www.openwall.com/lists/oss-security/2024/03/28/2", + "http://www.openwall.com/lists/oss-security/2024/03/27/9", + "http://www.openwall.com/lists/oss-security/2024/03/28/3", + "https://lists.debian.org/debian-lts-announce/2024/04/msg00005.html", + "https://www.openwall.com/lists/oss-security/2024/03/27/5", + "https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/", + "https://security.netapp.com/advisory/ntap-20240531-0003/", + "https://github.com/util-linux/util-linux/security/advisories/GHSA-xv2h-c6ww-mrjq", + "https://security-tracker.debian.org/tracker/CVE-2024-28085", + "http://www.openwall.com/lists/oss-security/2024/03/27/5", + "http://www.openwall.com/lists/oss-security/2024/03/28/1", + "https://github.com/skyler-ferrante/CVE-2024-28085", + "https://people.rit.edu/sjf5462/6831711781/wall_2_27_2024.txt", + "http://www.openwall.com/lists/oss-security/2024/03/27/7", + "http://www.openwall.com/lists/oss-security/2024/03/27/6" + ], + "extended_information": { + "short_description": "Escape character injection in util-linux wall may allow for data leakage by local attackers in specific scenarios", + "full_description": "[util-linux](https://github.com/util-linux/util-linux) is a random collection of Linux utilities. \nwall (write all) allows a user to send a text message to all other users (terminals) in the system.\nIt was discovered that wall does not filter escape sequences from command line arguments, allowing a local user to inject escape characters into other users' terminals.\n\nThis vulnerability can be used in a per-target social engineering attack, where the local attacker injects seemingly innocent text to other users' terminals, making them write sensitive information (ex. their password) which can subsequently be leaked to local files, depending on the exact scenario.\n\nWhile an example PoC demonstrated the possibility to leak user passwords when the victim uses `sudo`, in reality exploitation of this issue requires the attacker to deeply research the affected system and requires the victim's interaction, making it difficult to exploit even in low volumes.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The `wall` executable must have `setgid` permissions in order to be vulnerable. In addition, the victim's terminal must accept messages from other terminals (controlled via the `mesg` utility).", + "is_positive": true + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "The injected escape characters may allow the local attacker to social engineer a victim on the same machine. The impact of exploiting the vulnerability depends on what actions are performed by the victim user, but in most cases will lead to local privilege escalation of the attacker.", + "is_positive": true + }, + { + "name": "Exploiting the issue requires the user to interact with the vulnerable software", + "description": "The victim must interact with the injected escape characters in some way to cause code execution or data leakage. The injected escape characters cannot cause any harm on their own, only assist the attacker with social engineering.", + "is_positive": true + }, + { + "name": "The issue is trivial to exploit and does not require a published writeup or PoC", + "description": "A local attacker can simply call `exec` with `wall`, supplying escape characters in `argv` -\n```c\nexecve(\"/usr/bin/wall\", argv, envp);\n```" + } + ], + "remediation": "##### Deployment mitigations\n\nDisable write access of other users to your terminal -\n```bash\nmesg n\n```\n\n##### Deployment mitigations\n\nRemove the setgid permissions from wall -\n```bash\nsudo chmod g-s `which wall`\n```" + } + }, + { + "cves": [ + { + "cve": "CVE-2022-0563", + "cvss_v2_score": "1.9", + "cvss_v2_vector": "CVSS:2.0/AV:L/AC:M/Au:N/C:P/I:N/A:N", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", + "cwe": [ + "CWE-209" + ], + "cwe_details": { + "CWE-209": { + "name": "Generation of Error Message Containing Sensitive Information", + "description": "The product generates an error message that includes sensitive information about its environment, users, or associated data." + } + } + } + ], + "summary": "A flaw was found in the util-linux chfn and chsh utilities when compiled with Readline support. The Readline library uses an \"INPUTRC\" environment variable to get a path to the library config file. When the library cannot parse the specified file, it prints an error message containing data from the file. This flaw allows an unprivileged user to read root-owned files, potentially leading to privilege escalation. This flaw affects util-linux versions prior to 2.37.4.", + "severity": "Low", + "components": { + "deb://debian:bookworm:bsdutils:1:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:bsdutils:1:2.38.1-5+b1", + "full_path": "bsdutils:1:2.38.1-5+b1" + } + ] + ] + }, + "deb://debian:bookworm:libblkid1:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libblkid1:2.38.1-5+b1", + "full_path": "libblkid1:2.38.1-5+b1" + } + ] + ] + }, + "deb://debian:bookworm:libmount1:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libmount1:2.38.1-5+b1", + "full_path": "libmount1:2.38.1-5+b1" + } + ] + ] + }, + "deb://debian:bookworm:libsmartcols1:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libsmartcols1:2.38.1-5+b1", + "full_path": "libsmartcols1:2.38.1-5+b1" + } + ] + ] + }, + "deb://debian:bookworm:libuuid1:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libuuid1:2.38.1-5+b1", + "full_path": "libuuid1:2.38.1-5+b1" + } + ] + ] + }, + "deb://debian:bookworm:mount:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:mount:2.38.1-5+b1", + "full_path": "mount:2.38.1-5+b1" + } + ] + ] + }, + "deb://debian:bookworm:util-linux-extra:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:util-linux-extra:2.38.1-5+b1", + "full_path": "util-linux-extra:2.38.1-5+b1" + } + ] + ] + }, + "deb://debian:bookworm:util-linux:2.38.1-5+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:util-linux:2.38.1-5+b1", + "full_path": "util-linux:2.38.1-5+b1" + } + ] + ] + } + }, + "issue_id": "XRAY-198072", + "references": [ + "https://lore.kernel.org/util-linux/20220214110609.msiwlm457ngoic6w%40ws.net.home/T/#u", + "https://security.netapp.com/advisory/ntap-20220331-0002/", + "https://security-tracker.debian.org/tracker/CVE-2022-0563", + "https://security.gentoo.org/glsa/202401-08" + ], + "extended_information": { + "short_description": "Improper file-read in util-linux chsh and chfn tools can lead to sensitive data leakage when an attacker controls the INPUTRC environment variable.", + "full_description": "[util-linux](https://github.com/util-linux/util-linux) is a random collection of Linux utilities.\n`chsh` is used to change the login shell. `chfn` is used to change finger information.\n\nThe [GNU Readline library](https://tiswww.case.edu/php/chet/readline/rltop.html) provides a set of functions for use by applications that allow users to edit command lines as they are typed in. The Readline library is loads a library configuration file, passed via the `INPUTRC` environment variable.\n\nWhen the `chsh` and `chfn` are compiled with the `readline` library, and the `INPUTRC` environment variable is defined to a non-valid library config file, it will print an error message and leak some data from the malformed config file. \n\nThe major Linux distributions: Alpine, Debian and Ubuntu don’t use the `util-linux` package to compile `chsh` and `chfn` - instead they use the `shadow` package which isn’t vulnerable to this issue.\n\nAlso, Red Hat compiles `util-linux` without linking the vulnerable `readline` library.\n\nSince both of these tools have root-`setuid` permissions by default, a local attacker can in theory leak partial data from arbitrary (root-owned) files in the system by running them with an arbitrary `INPUTRC` environment variable.\n\nBut, when manually compiling `util-linux` from a vulnerable source, and installing this version on the system, the utilities lose their `setuid` flag. This is a feature of Linux systems that removes the `setuid` after a file has been modified. It must be manually enabled again using `chmod u+s` to read root-owned files.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The issue can only be exploited by an attacker that can execute code on the vulnerable machine (excluding exceedingly rare circumstances)", + "is_positive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "All the major Linux distributions don’t use a vulnerable version of the tools. Also, when manually compiling the tools from the source, the `setuid` flag is removed from the tools, thus losing access to leak the contents from root-owned files.", + "is_positive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Partial file data leakage", + "is_positive": true + }, + { + "name": "The issue is trivial to exploit and does not require a published writeup or PoC", + "description": "A local attacker may set the `INPUTRC` environment variable to an arbitrary file that should be leaked" + } + ], + "remediation": "##### Deployment mitigations\n\nIf a vulnerable version of `util-linux` was compiled manually, remove the SUID bit from the `chsh` and `chfn` tools using the `chmod u-s` command on them." + } + }, + { + "cves": [ + { + "cve": "CVE-2022-3219", + "cvss_v3_score": "3.3", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "GnuPG can be made to spin on a relatively small input by (for example) crafting a public key with thousands of signatures attached, compressed down to just a few KB.", + "severity": "Low", + "components": { + "deb://debian:bookworm:gpgv:2.2.40-1.1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:gpgv:2.2.40-1.1", + "full_path": "gpgv:2.2.40-1.1" + } + ] + ] + } + }, + "issue_id": "XRAY-425648", + "references": [ + "https://marc.info/?l=oss-security\u0026m=165696590211434\u0026w=4", + "https://security-tracker.debian.org/tracker/CVE-2022-3219", + "https://dev.gnupg.org/D556", + "https://security.netapp.com/advisory/ntap-20230324-0001/", + "https://bugzilla.redhat.com/show_bug.cgi?id=2127010", + "https://dev.gnupg.org/T5993", + "https://access.redhat.com/security/cve/CVE-2022-3219" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-39804" + } + ], + "summary": "In GNU tar before 1.35, mishandled extension attributes in a PAX archive can lead to an application crash in xheader.c.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:tar:1.34+dfsg-1.2": { + "fixed_versions": [ + "[1.34+dfsg-1.2+deb12u1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:tar:1.34+dfsg-1.2", + "full_path": "tar:1.34+dfsg-1.2" + } + ] + ] + } + }, + "issue_id": "XRAY-540509", + "references": [ + "https://git.savannah.gnu.org/cgit/tar.git/commit/?id=a339f05cd269013fa133d2f148d73f6f7d4247e4", + "https://git.savannah.gnu.org/cgit/tar.git/tree/src/xheader.c?h=release_1_34#n1723", + "https://security-tracker.debian.org/tracker/CVE-2023-39804", + "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1058079" + ] + }, + { + "cves": [ + { + "cve": "CVE-2005-2541", + "cvss_v2_score": "10.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:C/I:C/A:C", + "cwe": [ + "NVD-CWE-Other" + ] + } + ], + "summary": "Tar 1.15.1 does not properly warn the user when extracting setuid or setgid files, which may allow local users or remote attackers to gain privileges.", + "severity": "Low", + "components": { + "deb://debian:bookworm:tar:1.34+dfsg-1.2": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:tar:1.34+dfsg-1.2", + "full_path": "tar:1.34+dfsg-1.2" + } + ] + ] + } + }, + "issue_id": "XRAY-28223", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2005-2541", + "https://lists.apache.org/thread.html/rc713534b10f9daeee2e0990239fa407e2118e4aa9e88a7041177497c%40%3Cissues.guacamole.apache.org%3E", + "http://marc.info/?l=bugtraq\u0026m=112327628230258\u0026w=2" + ], + "extended_information": { + "short_description": "Preserving SETUID/SETGID bits when extracting with tar may lead to privilege escalation.", + "full_description": "When running as the \"root\" user, tar will restore by default the original permissions to any extracted files (this can be controlled via the `-p` argument). One of the restored permission bits are the SETUID/SETGID bits which make the extracted executable automatically elevate to \"root\" privileges, regardless of the user that ran the executable.\n\nThis behavior could be an issue when the root user extracts a crafted tar archive, which contains a SUID-enabled malicious executable, that allows privilege escalation.\nDe-facto, this behavior is widely known, documented and accepted behavior, and as such this issue did not receive a fix.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "Exploiting the issue requires the user to interact with the vulnerable software", + "description": "A root user must extract the \"affected\" tar archive", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must find a vulnerability in the extracted SETUID program in order to run arbitrary code, or alternatively make the root user extract an attacker-crafted tar archive", + "is_positive": true + }, + { + "name": "The issue cannot be exploited on its own, and can only be used as part of an attack chain", + "description": "Simply preserving the SETUID/SETGID bits will not lead to privilege escalation. The extracted program must still have a vulnerability that will allow the unprivileged user to achieve arbitrary (local) code execution", + "is_positive": true + }, + { + "name": "The issue has been disputed by the vendor", + "description": "Both Red Hat and Debian security trackers disputed the issue, citing \"This is the documented and expected behaviour of tar.\"", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2022-48303", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-125" + ], + "cwe_details": { + "CWE-125": { + "name": "Out-of-bounds Read", + "description": "The product reads data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "7" + } + ] + } + } + } + ], + "summary": "GNU Tar through 1.34 has a one-byte out-of-bounds read that results in use of uninitialized memory for a conditional jump. Exploitation to change the flow of control has not been demonstrated. The issue occurs in from_header in list.c via a V7 archive in which mtime has approximately 11 whitespace characters.", + "severity": "Low", + "components": { + "deb://debian:bookworm:tar:1.34+dfsg-1.2": { + "fixed_versions": [ + "[1.34+dfsg-1.2+deb12u1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:tar:1.34+dfsg-1.2", + "full_path": "tar:1.34+dfsg-1.2" + } + ] + ] + } + }, + "issue_id": "XRAY-414652", + "references": [ + "https://savannah.gnu.org/bugs/?62387", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/CRY7VEL4AIG3GLIEVCTOXRZNSVYDYYUD/", + "https://security-tracker.debian.org/tracker/CVE-2022-48303", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/X5VQYCO52Z7GAVCLRYUITN7KXHLRZQS4/", + "https://savannah.gnu.org/patch/?10307" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-25062", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-416" + ], + "cwe_details": { + "CWE-416": { + "name": "Use After Free", + "description": "Referencing memory after it has been freed can cause a program to crash, use unexpected values, or execute code.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "4" + } + ] + } + } + } + ], + "summary": "An issue was discovered in libxml2 before 2.11.7 and 2.12.x before 2.12.5. When using the XML Reader interface with DTD validation and XInclude expansion enabled, processing crafted XML documents can lead to an xmlValidatePopElement use-after-free.", + "severity": "High", + "components": { + "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1": { + "fixed_versions": [ + "[2.12.7+dfsg-1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1", + "full_path": "libxml2:2.9.14+dfsg-1.3~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-589897", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-25062", + "https://gitlab.gnome.org/GNOME/libxml2/-/tags", + "https://gitlab.gnome.org/GNOME/libxml2/-/issues/604" + ], + "extended_information": { + "short_description": "A use-after-free in libxml2 may lead to denial of service when parsing a crafted XML document with specific parser arguments.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "Exploiting this issue using static XML requires that the `XML_PARSE_XINCLUDE` (--xinclude) and the `XML_PARSE_VALIDATE` (--valid) flags are used.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Exploiting the vulnerability may lead to denial of service." + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS score does not take into account the contextual prerequisites required to exploit the vulnerability.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "A PoC that triggers the use-after-free is available in the Git issue." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must be able to control an XML file that is getting parsed by `xmlTextReaderRead()` with the xinclude and DTD validation options enabled. This can be achieved by passing both the `XML_PARSE_XINCLUDE` (--xinclude) and `XML_PARSE_VALIDATE` (--valid) flags when parsing the document.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-45322", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-416" + ], + "cwe_details": { + "CWE-416": { + "name": "Use After Free", + "description": "Referencing memory after it has been freed can cause a program to crash, use unexpected values, or execute code.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "4" + } + ] + } + } + } + ], + "summary": "libxml2 through 2.11.5 has a use-after-free that can only occur after a certain memory allocation fails. This occurs in xmlUnlinkNode in tree.c. NOTE: the vendor's position is \"I don't think these issues are critical enough to warrant a CVE ID ... because an attacker typically can't control when memory allocations fail.\"", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1": { + "fixed_versions": [ + "[2.12.7+dfsg-1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1", + "full_path": "libxml2:2.9.14+dfsg-1.3~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-533060", + "references": [ + "https://gitlab.gnome.org/GNOME/libxml2/-/issues/583", + "http://www.openwall.com/lists/oss-security/2023/10/06/5", + "https://security-tracker.debian.org/tracker/CVE-2023-45322", + "https://gitlab.gnome.org/GNOME/libxml2/-/issues/344" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-34459" + } + ], + "summary": "An issue was discovered in xmllint (from libxml2) before 2.11.8 and 2.12.x before 2.12.7. Formatting error messages with xmllint --htmlout can result in a buffer over-read in xmlHTMLPrintFileContext in xmllint.c.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1": { + "fixed_versions": [ + "[2.12.7+dfsg-1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1", + "full_path": "libxml2:2.9.14+dfsg-1.3~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-601044", + "references": [ + "https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.12.7", + "https://security-tracker.debian.org/tracker/CVE-2024-34459", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/INKSSLW5VMZIXHRPZBAW4TJUX5SQKARG/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/VRDJCNQP32LV56KESUQ5SNZKAJWSZZRI/", + "https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.11.8", + "https://gitlab.gnome.org/GNOME/libxml2/-/issues/720", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/5HVUXKYTBWT3G5DEEQX62STJQBY367NL/" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-39615", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-119" + ], + "cwe_details": { + "CWE-119": { + "name": "Improper Restriction of Operations within the Bounds of a Memory Buffer", + "description": "The product performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "17" + } + ] + } + } + } + ], + "summary": "Xmlsoft Libxml2 v2.11.0 was discovered to contain an out-of-bounds read via the xmlSAX2StartElement() function at /libxml2/SAX2.c. This vulnerability allows attackers to cause a Denial of Service (DoS) via supplying a crafted XML file. NOTE: the vendor's position is that the product does not support the legacy SAX1 interface with custom callbacks; there is a crash even without crafted input.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1": { + "fixed_versions": [ + "[2.12.7+dfsg-1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1", + "full_path": "libxml2:2.9.14+dfsg-1.3~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-529332", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-39615", + "https://gitlab.gnome.org/GNOME/libxml2/-/issues/535" + ] + }, + { + "cves": [ + { + "cve": "CVE-2019-19882", + "cvss_v2_score": "6.9", + "cvss_v2_vector": "CVSS:2.0/AV:L/AC:M/Au:N/C:C/I:C/A:C", + "cvss_v3_score": "7.8", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-732" + ], + "cwe_details": { + "CWE-732": { + "name": "Incorrect Permission Assignment for Critical Resource", + "description": "The product specifies permissions for a security-critical resource in a way that allows that resource to be read or modified by unintended actors." + } + } + } + ], + "summary": "shadow 4.8, in certain circumstances affecting at least Gentoo, Arch Linux, and Void Linux, allows local users to obtain root access because setuid programs are misconfigured. Specifically, this affects shadow 4.8 when compiled using --with-libpam but without explicitly passing --disable-account-tools-setuid, and without a PAM configuration suitable for use with setuid account management tools. This combination leads to account management tools (groupadd, groupdel, groupmod, useradd, userdel, usermod) that can easily be used by unprivileged local users to escalate privileges to root in multiple ways. This issue became much more relevant in approximately December 2019 when an unrelated bug was fixed (i.e., the chmod calls to suidusbins were fixed in the upstream Makefile which is now included in the release version 4.8).", + "severity": "Low", + "components": { + "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1", + "full_path": "login:1:4.13+dfsg1-1+b1" + } + ] + ] + }, + "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1", + "full_path": "passwd:1:4.13+dfsg1-1+b1" + } + ] + ] + } + }, + "issue_id": "XRAY-93202", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2019-19882", + "https://github.com/shadow-maint/shadow/commit/edf7547ad5aa650be868cf2dac58944773c12d75", + "https://bugs.gentoo.org/702252", + "https://security.gentoo.org/glsa/202008-09", + "https://github.com/shadow-maint/shadow/pull/199", + "https://bugs.archlinux.org/task/64836", + "https://github.com/void-linux/void-packages/pull/17580" + ] + }, + { + "cves": [ + { + "cve": "CVE-2007-5686", + "cvss_v2_score": "4.9", + "cvss_v2_vector": "CVSS:2.0/AV:L/AC:L/Au:N/C:C/I:N/A:N", + "cwe": [ + "CWE-264" + ] + } + ], + "summary": "initscripts in rPath Linux 1 sets insecure permissions for the /var/log/btmp file, which allows local users to obtain sensitive information regarding authentication attempts. NOTE: because sshd detects the insecure permissions and does not log certain events, this also prevents sshd from logging failed authentication attempts by remote attackers.", + "severity": "Low", + "components": { + "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1", + "full_path": "login:1:4.13+dfsg1-1+b1" + } + ] + ] + }, + "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1", + "full_path": "passwd:1:4.13+dfsg1-1+b1" + } + ] + ] + } + }, + "issue_id": "XRAY-37289", + "references": [ + "http://www.securityfocus.com/archive/1/482857/100/0/threaded", + "http://www.securityfocus.com/archive/1/482129/100/100/threaded", + "http://www.securityfocus.com/bid/26048", + "http://www.vupen.com/english/advisories/2007/3474", + "https://security-tracker.debian.org/tracker/CVE-2007-5686", + "https://issues.rpath.com/browse/RPL-1825", + "http://secunia.com/advisories/27215" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-4641", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", + "cwe": [ + "CWE-287" + ], + "cwe_details": { + "CWE-287": { + "name": "Improper Authentication", + "description": "When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "13" + } + ] + } + } + } + ], + "summary": "A flaw was found in shadow-utils. When asking for a new password, shadow-utils asks the password twice. If the password fails on the second attempt, shadow-utils fails in cleaning the buffer used to store the first entry. This may allow an attacker with enough access to retrieve the password from the memory.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1", + "full_path": "login:1:4.13+dfsg1-1+b1" + } + ] + ] + }, + "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1", + "full_path": "passwd:1:4.13+dfsg1-1+b1" + } + ] + ] + } + }, + "issue_id": "XRAY-529509", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-4641", + "https://access.redhat.com/errata/RHSA-2024:2577", + "https://access.redhat.com/security/cve/CVE-2023-4641", + "https://access.redhat.com/errata/RHSA-2023:6632", + "https://bugzilla.redhat.com/show_bug.cgi?id=2215945", + "https://access.redhat.com/errata/RHSA-2024:0417", + "https://access.redhat.com/errata/RHSA-2023:7112" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-29383", + "cvss_v3_score": "3.3", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N", + "cwe": [ + "CWE-74" + ], + "cwe_details": { + "CWE-74": { + "name": "Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')", + "description": "The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component." + } + } + } + ], + "summary": "In Shadow 4.13, it is possible to inject control characters into fields provided to the SUID program chfn (change finger). Although it is not possible to exploit this directly (e.g., adding a new user fails because \\n is in the block list), it is possible to misrepresent the /etc/passwd file when viewed. Use of \\r manipulations and Unicode characters to work around blocking of the : character make it possible to give the impression that a new user has been added. In other words, an adversary may be able to convince a system administrator to take the system offline (an indirect, social-engineered denial of service) by demonstrating that \"cat /etc/passwd\" shows a rogue user account.", + "severity": "Low", + "components": { + "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1", + "full_path": "login:1:4.13+dfsg1-1+b1" + } + ] + ] + }, + "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1", + "full_path": "passwd:1:4.13+dfsg1-1+b1" + } + ] + ] + } + }, + "issue_id": "XRAY-513968", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-29383", + "https://github.com/shadow-maint/shadow/pull/687", + "https://github.com/shadow-maint/shadow/commit/e5905c4b84d4fb90aefcd96ee618411ebfac663d", + "https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/cve-2023-29383-abusing-linux-chfn-to-misrepresent-etc-passwd/", + "https://www.trustwave.com/en-us/resources/security-resources/security-advisories/?fid=31797" + ] + }, + { + "cves": [ + { + "cve": "CVE-2017-9937", + "cvss_v2_score": "4.3", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:N/A:P", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-119" + ], + "cwe_details": { + "CWE-119": { + "name": "Improper Restriction of Operations within the Bounds of a Memory Buffer", + "description": "The product performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "17" + } + ] + } + } + } + ], + "summary": "In LibTIFF 4.0.8, there is a memory malloc failure in tif_jbig.c. A crafted TIFF document can lead to an abort resulting in a remote denial of service attack.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libjbig0:2.1-6.1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libjbig0:2.1-6.1", + "full_path": "libjbig0:2.1-6.1" + } + ] + ] + } + }, + "issue_id": "XRAY-56874", + "references": [ + "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772%40%3Cdev.mina.apache.org%3E", + "http://bugzilla.maptools.org/show_bug.cgi?id=2707", + "https://security-tracker.debian.org/tracker/CVE-2017-9937", + "http://www.securityfocus.com/bid/99304" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-2511" + } + ], + "summary": "Issue summary: Some non-default TLS server configurations can cause unbounded\nmemory growth when processing TLSv1.3 sessions\n\nImpact summary: An attacker may exploit certain server configurations to trigger\nunbounded memory growth that would lead to a Denial of Service\n\nThis problem can occur in TLSv1.3 if the non-default SSL_OP_NO_TICKET option is\nbeing used (but not if early_data support is also configured and the default\nanti-replay protection is in use). In this case, under certain conditions, the\nsession cache can get into an incorrect state and it will fail to flush properly\nas it fills. The session cache will continue to grow in an unbounded manner. A\nmalicious client could deliberately create the scenario for this failure to\nforce a Denial of Service. It may also happen by accident in normal operation.\n\nThis issue only affects TLS servers supporting TLSv1.3. It does not affect TLS\nclients.\n\nThe FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue. OpenSSL\n1.0.2 is also not affected by this issue.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "fixed_versions": [ + "[3.0.14-1~deb12u1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-597548", + "references": [ + "https://github.com/openssl/openssl/commit/e9d7083e241670332e0443da0f0d4ffb52829f08", + "https://github.com/openssl/openssl/commit/7e4d731b1c07201ad9374c1cd9ac5263bdf35bce", + "https://github.openssl.org/openssl/extended-releases/commit/5f8d25770ae6437db119dfc951e207271a326640", + "https://github.com/openssl/openssl/commit/b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d", + "https://security-tracker.debian.org/tracker/CVE-2024-2511", + "https://www.openssl.org/news/secadv/20240408.txt", + "http://www.openwall.com/lists/oss-security/2024/04/08/5", + "https://security.netapp.com/advisory/ntap-20240503-0013/" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-6129", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "Issue summary: The POLY1305 MAC (message authentication code) implementation\ncontains a bug that might corrupt the internal state of applications running\non PowerPC CPU based platforms if the CPU provides vector instructions.\n\nImpact summary: If an attacker can influence whether the POLY1305 MAC\nalgorithm is used, the application state might be corrupted with various\napplication dependent consequences.\n\nThe POLY1305 MAC (message authentication code) implementation in OpenSSL for\nPowerPC CPUs restores the contents of vector registers in a different order\nthan they are saved. Thus the contents of some of these vector registers\nare corrupted when returning to the caller. The vulnerable code is used only\non newer PowerPC processors supporting the PowerISA 2.07 instructions.\n\nThe consequences of this kind of internal application state corruption can\nbe various - from no consequences, if the calling application does not\ndepend on the contents of non-volatile XMM registers at all, to the worst\nconsequences, where the attacker could get complete control of the application\nprocess. However unless the compiler uses the vector registers for storing\npointers, the most likely consequence, if any, would be an incorrect result\nof some application dependent calculations or a crash leading to a denial of\nservice.\n\nThe POLY1305 MAC algorithm is most frequently used as part of the\nCHACHA20-POLY1305 AEAD (authenticated encryption with associated data)\nalgorithm. The most common usage of this AEAD cipher is with TLS protocol\nversions 1.2 and 1.3. If this cipher is enabled on the server a malicious\nclient can influence whether this AEAD cipher is used. This implies that\nTLS server applications using OpenSSL can be potentially impacted. However\nwe are currently not aware of any concrete application that would be affected\nby this issue therefore we consider this a Low severity security issue.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "fixed_versions": [ + "[3.0.13-1~deb12u1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-588102", + "references": [ + "https://security.netapp.com/advisory/ntap-20240426-0008/", + "https://security.netapp.com/advisory/ntap-20240426-0013/", + "http://www.openwall.com/lists/oss-security/2024/03/11/1", + "https://github.com/openssl/openssl/commit/f3fc5808fe9ff74042d639839610d03b8fdcc015", + "https://github.com/openssl/openssl/commit/050d26383d4e264966fb83428e72d5d48f402d35", + "https://security.netapp.com/advisory/ntap-20240216-0009/", + "https://www.openssl.org/news/secadv/20240109.txt", + "https://security-tracker.debian.org/tracker/CVE-2023-6129", + "https://github.com/openssl/openssl/commit/5b139f95c9a47a55a0c54100f3837b1eee942b04", + "https://security.netapp.com/advisory/ntap-20240503-0011/" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-6119" + } + ], + "summary": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "fixed_versions": [ + "[3.0.14-1~deb12u2]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-632747", + "references": [ + "https://openssl-library.org/news/secadv/20240903.txt", + "https://github.com/openssl/openssl/commit/621f3729831b05ee828a3203eddb621d014ff2b2", + "https://github.com/openssl/openssl/commit/05f360d9e849a1b277db628f1f13083a7f8dd04f", + "https://security-tracker.debian.org/tracker/CVE-2024-6119", + "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6", + "https://github.com/openssl/openssl/commit/7dfcee2cd2a63b2c64b9b4b0850be64cb695b0a0" + ], + "extended_information": { + "short_description": "Out of bounds read in OpenSSL clients can lead to denial of service when using non-default TLS verification options and connecting to malicious TLS servers", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "The fix commit contains PoC certificates that trigger the denial of service issue" + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker must make the victim client connect to their malicious TLS server, in order to serve the malformed TLS certificate. The victim client must use OpenSSL and must enable non-default certificate verification options, either -\n\n* DNS verification - by using `X509_VERIFY_PARAM_set1_host` or `X509_check_host`\n* Email verification - by using ` X509_VERIFY_PARAM_set1_email` or `X509_check_email`", + "is_positive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Denial of service of a TLS clients only. This out of bounds read cannot lead to data disclosure.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-5363", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", + "cwe": [ + "NVD-CWE-noinfo" + ] + } + ], + "summary": "Issue summary: A bug has been identified in the processing of key and\ninitialisation vector (IV) lengths. This can lead to potential truncation\nor overruns during the initialisation of some symmetric ciphers.\n\nImpact summary: A truncation in the IV can result in non-uniqueness,\nwhich could result in loss of confidentiality for some cipher modes.\n\nWhen calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or\nEVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after\nthe key and IV have been established. Any alterations to the key length,\nvia the \"keylen\" parameter or the IV length, via the \"ivlen\" parameter,\nwithin the OSSL_PARAM array will not take effect as intended, potentially\ncausing truncation or overreading of these values. The following ciphers\nand cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.\n\nFor the CCM, GCM and OCB cipher modes, truncation of the IV can result in\nloss of confidentiality. For example, when following NIST's SP 800-38D\nsection 8.2.1 guidance for constructing a deterministic IV for AES in\nGCM mode, truncation of the counter portion could lead to IV reuse.\n\nBoth truncations and overruns of the key and overruns of the IV will\nproduce incorrect results and could, in some cases, trigger a memory\nexception. However, these issues are not currently assessed as security\ncritical.\n\nChanging the key and/or IV lengths is not considered to be a common operation\nand the vulnerable API was recently introduced. Furthermore it is likely that\napplication developers will have spotted this problem during testing since\ndecryption would fail unless both peers in the communication were similarly\nvulnerable. For these reasons we expect the probability of an application being\nvulnerable to this to be quite low. However if an application is vulnerable then\nthis issue is considered very serious. For these reasons we have assessed this\nissue as Moderate severity overall.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\n\nThe OpenSSL 3.0 and 3.1 FIPS providers are...", + "severity": "High", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "fixed_versions": [ + "[3.0.11-1~deb12u2]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-534361", + "references": [ + "https://security.netapp.com/advisory/ntap-20231027-0010/", + "https://www.openssl.org/news/secadv/20231024.txt", + "https://security-tracker.debian.org/tracker/CVE-2023-5363", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=5f69f5c65e483928c4b28ed16af6e5742929f1ee", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=0df40630850fb2740e6be6890bb905d3fc623b2d", + "https://www.debian.org/security/2023/dsa-5532", + "https://security.netapp.com/advisory/ntap-20240201-0004/", + "http://www.openwall.com/lists/oss-security/2023/10/24/1", + "https://security.netapp.com/advisory/ntap-20240201-0003/" + ], + "extended_information": { + "short_description": "A design problem in OpenSSL 3.x may lead to data leakage when processing cipher parameters.", + "full_description": "OpenSSL is an open-source cryptographic library and toolset that provides a wide range of protocol supported and functions for secure communication, data encryption, digital certificates, and other cryptographic operations, widely used in various software applications and systems.\nIn cryptography, a block cipher is a symmetric key algorithm that encrypts fixed-size blocks of data, typically 64 or 128 bits, transforming each block into a corresponding ciphertext block using a key-specific permutation.\n\nA major problem with block ciphers, is that equal plaintext blocks get transformed to equal ciphertexts. This can be used for a known-plaintext attack, where an adversary possesses both the plaintext and its corresponding encrypted form, aiming to deduce the encryption key or gain insights into the encryption algorithm.\n\nTo counter this, we use an Initialization vector (IV), which is a random or unique input to a cryptographic algorithm used to alter the first block of the cipher, ensuring equal plaintext blocks won’t be transformed to equal ciphertexts.\n\nA vulnerability was found in OpenSSL 3.x, in certain situations, parameters such as key length or IV length, will be processed after the key and IV have been established, hence they will not take effect as intended, potentially causing truncation or overreading of these values, impacting the confidentiality of the encryption.\n\nWhen calling the functions `EVP_CipherInit_ex2`, `EVP_EncryptInit_ex2, or `EVP_DecryptInit_ex2` with an `OSSL_PARAM` array, changes to the `keylen` or `ivlen` parameters will only be processed after the IV and the key have been established.\n\nNote this impacts the following ciphers: RC2, RC4, RC5, and the following cipher modes: CCM, GCM, OCB.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The vulnerability is only applicable if the vulnerable functions `EVP_CipherInit_ex2`, `EVP_EncryptInit_ex2, or `EVP_DecryptInit_ex2` is called directly or indirectly with an `OSSL_PARAM` array that alters the `ivlen` and `keylen` parameters. Moreover, it only impacts the following ciphers: RC2, RC4, RC5, and the following cipher modes: CCM, GCM, OCB.", + "is_positive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "Changing the key or IV lengths is not considered a popular operation. Furthermore, the API only affects OpenSSL 3.x and it is likely the app developers have discovered the problem during testing, as it would have caused the decryption to fail.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The given CVSS score does not take into account the unlikely prerequisites and the context required to exploit this CVE.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "In the case that this vulnerability is exploited successfully, an attacker can read sensitive data as plaintext, breaking the encryption." + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2024-4603" + } + ], + "summary": "Issue summary: Checking excessively long DSA keys or parameters may be very\nslow.\n\nImpact summary: Applications that use the functions EVP_PKEY_param_check()\nor EVP_PKEY_public_check() to check a DSA public key or DSA parameters may\nexperience long delays. Where the key or parameters that are being checked\nhave been obtained from an untrusted source this may lead to a Denial of\nService.\n\nThe functions EVP_PKEY_param_check() or EVP_PKEY_public_check() perform\nvarious checks on DSA parameters. Some of those computations take a long time\nif the modulus (`p` parameter) is too large.\n\nTrying to use a very large modulus is slow and OpenSSL will not allow using\npublic keys with a modulus which is over 10,000 bits in length for signature\nverification. However the key and parameter check functions do not limit\nthe modulus size when performing the checks.\n\nAn application that calls EVP_PKEY_param_check() or EVP_PKEY_public_check()\nand supplies a key or parameters obtained from an untrusted source could be\nvulnerable to a Denial of Service attack.\n\nThese functions are not called by OpenSSL itself on untrusted DSA keys so\nonly applications that directly call these functions may be vulnerable.\n\nAlso vulnerable are the OpenSSL pkey and pkeyparam command line applications\nwhen using the `-check` option.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\n\nThe OpenSSL 3.0 and 3.1 FIPS providers are affected by this issue.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "fixed_versions": [ + "[3.0.14-1~deb12u1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-601418", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-4603", + "https://security.netapp.com/advisory/ntap-20240621-0001/", + "https://github.com/openssl/openssl/commit/53ea06486d296b890d565fb971b2764fcd826e7e", + "http://www.openwall.com/lists/oss-security/2024/05/16/2", + "https://github.com/openssl/openssl/commit/3559e868e58005d15c6013a0c1fd832e51c73397", + "https://www.openssl.org/news/secadv/20240516.txt", + "https://github.com/openssl/openssl/commit/da343d0605c826ef197aceedc67e8e04f065f740", + "https://github.com/openssl/openssl/commit/9c39b3858091c152f52513c066ff2c5a47969f0d" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-0727", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "NVD-CWE-noinfo" + ] + } + ], + "summary": "Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL\nto crash leading to a potential Denial of Service attack\n\nImpact summary: Applications loading files in the PKCS12 format from untrusted\nsources might terminate abruptly.\n\nA file in PKCS12 format can contain certificates and keys and may come from an\nuntrusted source. The PKCS12 specification allows certain fields to be NULL, but\nOpenSSL does not correctly check for this case. This can lead to a NULL pointer\ndereference that results in OpenSSL crashing. If an application processes PKCS12\nfiles from an untrusted source using the OpenSSL APIs then that application will\nbe vulnerable to this issue.\n\nOpenSSL APIs that are vulnerable to this are: PKCS12_parse(),\nPKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes()\nand PKCS12_newpass().\n\nWe have also fixed a similar issue in SMIME_write_PKCS7(). However since this\nfunction is related to writing data we do not consider it security significant.\n\nThe FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "fixed_versions": [ + "[3.0.13-1~deb12u1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-589396", + "references": [ + "https://github.com/openssl/openssl/commit/d135eeab8a5dbf72b3da5240bab9ddb7678dbd2c", + "https://github.openssl.org/openssl/extended-releases/commit/03b3941d60c4bce58fab69a0c22377ab439bc0e8", + "https://security-tracker.debian.org/tracker/CVE-2024-0727", + "https://github.openssl.org/openssl/extended-releases/commit/aebaa5883e31122b404e450732dc833dc9dee539", + "https://www.openssl.org/news/secadv/20240125.txt", + "https://security.netapp.com/advisory/ntap-20240208-0006/", + "https://github.com/openssl/openssl/commit/775acfdbd0c6af9ac855f34969cdab0c0c90844a", + "https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2", + "http://www.openwall.com/lists/oss-security/2024/03/11/1" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-6237" + } + ], + "summary": "Issue summary: Checking excessively long invalid RSA public keys may take\na long time.\n\nImpact summary: Applications that use the function EVP_PKEY_public_check()\nto check RSA public keys may experience long delays. Where the key that\nis being checked has been obtained from an untrusted source this may lead\nto a Denial of Service.\n\nWhen function EVP_PKEY_public_check() is called on RSA public keys,\na computation is done to confirm that the RSA modulus, n, is composite.\nFor valid RSA keys, n is a product of two or more large primes and this\ncomputation completes quickly. However, if n is an overly large prime,\nthen this computation would take a long time.\n\nAn application that calls EVP_PKEY_public_check() and supplies an RSA key\nobtained from an untrusted source could be vulnerable to a Denial of Service\nattack.\n\nThe function EVP_PKEY_public_check() is not called from other OpenSSL\nfunctions however it is called from the OpenSSL pkey command line\napplication. For that reason that application is also vulnerable if used\nwith the '-pubin' and '-check' options on untrusted data.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\n\nThe OpenSSL 3.0 and 3.1 FIPS providers are affected by this issue.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "fixed_versions": [ + "[3.0.13-1~deb12u1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-588469", + "references": [ + "https://github.com/openssl/openssl/commit/a830f551557d3d66a84bbb18a5b889c640c36294", + "https://github.com/openssl/openssl/commit/18c02492138d1eb8b6548cb26e7b625fb2414a2a", + "https://github.com/openssl/openssl/commit/0b0f7abfb37350794a4b8960fafc292cd5d1b84d", + "https://security.netapp.com/advisory/ntap-20240531-0007/", + "https://www.openssl.org/news/secadv/20240115.txt", + "https://security-tracker.debian.org/tracker/CVE-2023-6237", + "http://www.openwall.com/lists/oss-security/2024/03/11/1" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-4741" + } + ], + "summary": "CVE-2024-4741", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "fixed_versions": [ + "[3.0.14-1~deb12u1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-603657", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-4741" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-5678", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "cwe": [ + "CWE-754" + ], + "cwe_details": { + "CWE-754": { + "name": "Improper Check for Unusual or Exceptional Conditions", + "description": "The product does not check or incorrectly checks for unusual or exceptional conditions that are not expected to occur frequently during day to day operation of the product." + } + } + } + ], + "summary": "Issue summary: Generating excessively long X9.42 DH keys or checking\nexcessively long X9.42 DH keys or parameters may be very slow.\n\nImpact summary: Applications that use the functions DH_generate_key() to\ngenerate an X9.42 DH key may experience long delays. Likewise, applications\nthat use DH_check_pub_key(), DH_check_pub_key_ex() or EVP_PKEY_public_check()\nto check an X9.42 DH key or X9.42 DH parameters may experience long delays.\nWhere the key or parameters that are being checked have been obtained from\nan untrusted source this may lead to a Denial of Service.\n\nWhile DH_check() performs all the necessary checks (as of CVE-2023-3817),\nDH_check_pub_key() doesn't make any of these checks, and is therefore\nvulnerable for excessively large P and Q parameters.\n\nLikewise, while DH_generate_key() performs a check for an excessively large\nP, it doesn't check for an excessively large Q.\n\nAn application that calls DH_generate_key() or DH_check_pub_key() and\nsupplies a key or parameters obtained from an untrusted source could be\nvulnerable to a Denial of Service attack.\n\nDH_generate_key() and DH_check_pub_key() are also called by a number of\nother OpenSSL functions. An application calling any of those other\nfunctions may similarly be affected. The other functions affected by this\nare DH_check_pub_key_ex(), EVP_PKEY_public_check(), and EVP_PKEY_generate().\n\nAlso vulnerable are the OpenSSL pkey command line application when using the\n\"-pubcheck\" option, as well as the OpenSSL genpkey command line application.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\n\nThe OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "fixed_versions": [ + "[3.0.13-1~deb12u1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-535129", + "references": [ + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=34efaef6c103d636ab507a0cc34dca4d3aecc055", + "https://security.netapp.com/advisory/ntap-20231130-0010/", + "http://www.openwall.com/lists/oss-security/2024/03/11/1", + "https://security-tracker.debian.org/tracker/CVE-2023-5678", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=710fee740904b6290fef0dd5536fbcedbc38ff0c", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=db925ae2e65d0d925adef429afc37f75bd1c2017", + "https://www.openssl.org/news/secadv/20231106.txt", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=ddeb4b6c6d527e54ce9a99cba785c0f7776e54b6" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-5535" + } + ], + "summary": "Issue summary: Calling the OpenSSL API function SSL_select_next_proto with an\nempty supported client protocols buffer may cause a crash or memory contents to\nbe sent to the peer.\n\nImpact summary: A buffer overread can have a range of potential consequences\nsuch as unexpected application beahviour or a crash. In particular this issue\ncould result in up to 255 bytes of arbitrary private data from memory being sent\nto the peer leading to a loss of confidentiality. However, only applications\nthat directly call the SSL_select_next_proto function with a 0 length list of\nsupported client protocols are affected by this issue. This would normally never\nbe a valid scenario and is typically not under attacker control but may occur by\naccident in the case of a configuration or programming error in the calling\napplication.\n\nThe OpenSSL API function SSL_select_next_proto is typically used by TLS\napplications that support ALPN (Application Layer Protocol Negotiation) or NPN\n(Next Protocol Negotiation). NPN is older, was never standardised and\nis deprecated in favour of ALPN. We believe that ALPN is significantly more\nwidely deployed than NPN. The SSL_select_next_proto function accepts a list of\nprotocols from the server and a list of protocols from the client and returns\nthe first protocol that appears in the server list that also appears in the\nclient list. In the case of no overlap between the two lists it returns the\nfirst item in the client list. In either case it will signal whether an overlap\nbetween the two lists was found. In the case where SSL_select_next_proto is\ncalled with a zero length client list it fails to notice this condition and\nreturns the memory immediately following the client list pointer (and reports\nthat there was no overlap in the lists).\n\nThis function is typically called from a server side application callback for\nALPN or a client side application callback for NPN. In the case of ALPN the list\nof protocols supplied by the client is guaranteed by libssl to never be zero in\nlength. The list of ...", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "fixed_versions": [ + "[3.3.2-1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-607811", + "references": [ + "https://security.netapp.com/advisory/ntap-20240712-0005/", + "https://www.openssl.org/news/secadv/20240627.txt", + "https://github.com/openssl/openssl/commit/cf6f91f6121f4db167405db2f0de410a456f260c", + "https://security-tracker.debian.org/tracker/CVE-2024-5535", + "http://www.openwall.com/lists/oss-security/2024/06/28/4", + "https://github.com/openssl/openssl/commit/99fb785a5f85315b95288921a321a935ea29a51e", + "http://www.openwall.com/lists/oss-security/2024/06/27/1", + "https://github.openssl.org/openssl/extended-releases/commit/b78ec0824da857223486660177d3b1f255c65d87", + "https://github.com/openssl/openssl/commit/e86ac436f0bd54d4517745483e2315650fae7b2c", + "https://github.com/openssl/openssl/commit/4ada436a1946cbb24db5ab4ca082b69c1bc10f37", + "https://github.openssl.org/openssl/extended-releases/commit/9947251413065a05189a63c9b7a6c1d4e224c21c" + ] + }, + { + "cves": [ + { + "cve": "CVE-2012-2131", + "cvss_v2_score": "7.5", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P", + "cwe": [ + "CWE-189" + ] + } + ], + "summary": "Multiple integer signedness errors in crypto/buffer/buffer.c in OpenSSL 0.9.8v allow remote attackers to conduct buffer overflow attacks, and cause a denial of service (memory corruption) or possibly have unspecified other impact, via crafted DER data, as demonstrated by an X.509 certificate or an RSA public key. NOTE: this vulnerability exists because of an incomplete fix for CVE-2012-2110.", + "severity": "High", + "components": { + "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", + "full_path": "libssl3:3.0.11-1~deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", + "full_path": "openssl:3.0.11-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-192416", + "references": [ + "http://www.openwall.com/lists/oss-security/2012/04/24/1", + "http://secunia.com/advisories/48956", + "http://lists.apple.com/archives/security-announce/2013/Jun/msg00000.html", + "http://www.ubuntu.com/usn/USN-1428-1", + "http://secunia.com/advisories/48895", + "http://www-01.ibm.com/support/docview.wss?uid=ssg1S1004564", + "http://www.mandriva.com/security/advisories?name=MDVSA-2012:064", + "http://www.debian.org/security/2012/dsa-2454", + "http://www.openssl.org/news/secadv_20120424.txt", + "http://lists.opensuse.org/opensuse-security-announce/2012-05/msg00014.html", + "http://lists.opensuse.org/opensuse-security-announce/2012-09/msg00007.html", + "http://www.securitytracker.com/id?1026957", + "http://secunia.com/advisories/57353", + "http://marc.info/?l=bugtraq\u0026m=134039053214295\u0026w=2", + "https://security-tracker.debian.org/tracker/CVE-2012-2131", + "http://cvs.openssl.org/chngview?cn=22479", + "http://marc.info/?l=bugtraq\u0026m=133728068926468\u0026w=2", + "http://kb.juniper.net/InfoCenter/index?page=content\u0026id=JSA10673", + "https://exchange.xforce.ibmcloud.com/vulnerabilities/75099", + "http://www.securityfocus.com/bid/53212", + "http://lists.opensuse.org/opensuse-security-announce/2012-05/msg00015.html", + "http://support.apple.com/kb/HT5784" + ] + }, + { + "cves": [ + { + "cve": "CVE-2011-3374", + "cvss_v2_score": "4.3", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:P/A:N", + "cvss_v3_score": "3.7", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N", + "cwe": [ + "CWE-347" + ], + "cwe_details": { + "CWE-347": { + "name": "Improper Verification of Cryptographic Signature", + "description": "The product does not verify, or incorrectly verifies, the cryptographic signature for data." + } + } + } + ], + "summary": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", + "severity": "Low", + "components": { + "deb://debian:bookworm:apt:2.6.1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:apt:2.6.1", + "full_path": "apt:2.6.1" + } + ] + ] + }, + "deb://debian:bookworm:libapt-pkg6.0:2.6.1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libapt-pkg6.0:2.6.1", + "full_path": "libapt-pkg6.0:2.6.1" + } + ] + ] + } + }, + "issue_id": "XRAY-34417", + "references": [ + "https://people.canonical.com/~ubuntu-security/cve/2011/CVE-2011-3374.html", + "https://seclists.org/fulldisclosure/2011/Sep/221", + "https://ubuntu.com/security/CVE-2011-3374", + "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=642480", + "https://access.redhat.com/security/cve/cve-2011-3374", + "https://snyk.io/vuln/SNYK-LINUX-APT-116518", + "https://security-tracker.debian.org/tracker/CVE-2011-3374" + ], + "extended_information": { + "short_description": "Improper signature validation in apt-key may enable Man-in-the-Middle attacks and result in code execution.", + "full_description": "`apt-key` is [`apt`](https://github.com/Debian/apt)'s key management utility, and is used to manage the keys that are used by `apt` to authenticate packages.\n\nA vulnerability in `apt-key`'s `net-update` function exists, in which [`GPG`](https://www.gnupg.org/) keys, that are used for signing packages and validating their authenticity, aren't validated correctly. The `net-update` function pulls the signing keys that should be added from an insecure location (`http://...`), exposing it to a Man-in-the-Middle attack in which malicious signing keys could be added to the system's keyring. This issue happens due to a vulnerability in the `add_keys_with_veirfy_against_master_keyring()` function, which allows adding signing keys without proper signature validation. \n\nThis vulnerability then potentially allows a malicious actor to perform a Man-in-the-Middle attack on a target, by making it validate malicious packages that were signed with the `GPG` signing key used by the attacker. Effectively, this means that `apt` can be duped to install malicious services and daemons with root privileges.\n\nThe conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man In The Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from [python-apt](https://pypi.org/project/python-apt/) Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.\n\nDo note that `apt-key` is **deprecated** and shouldn't be used, and in most Debian versions `ARCHIVE_KEYRING_URI` is not defined, making this vulnerability unexploitable in most Debian systems.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the python-apt Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", + "is_positive": true + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "This vulnerability is remotely exploitable when the applicability conditions apply." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Remote code execution is possible when the applicability conditions apply." + }, + { + "name": "The issue has an exploit published", + "description": "The reporter of this issue has provided a GPG key that can be used for an actual attack, as well as a simple PoC example." + } + ], + "remediation": "##### Deployment mitigations\n\n* Dot not execute `apt-key` command, as it is deprecated.\n* Remove the URI configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`." + } + }, + { + "cves": [ + { + "cve": "CVE-2023-4039", + "cvss_v3_score": "4.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", + "cwe": [ + "NVD-CWE-Other" + ] + } + ], + "summary": "**DISPUTED**A failure in the -fstack-protector feature in GCC-based toolchains \nthat target AArch64 allows an attacker to exploit an existing buffer \noverflow in dynamically-sized local variables in your application \nwithout this being detected. This stack-protector failure only applies \nto C99-style dynamically-sized local variables or those created using \nalloca(). The stack-protector operates as intended for statically-sized \nlocal variables.\n\nThe default behavior when the stack-protector \ndetects an overflow is to terminate your application, resulting in \ncontrolled loss of availability. An attacker who can exploit a buffer \noverflow without triggering the stack-protector might be able to change \nprogram flow control to cause an uncontrolled loss of availability or to\n go further and affect confidentiality or integrity. NOTE: The GCC project argues that this is a missed hardening bug and not a vulnerability by itself.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:gcc-12-base:12.2.0-14": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:gcc-12-base:12.2.0-14", + "full_path": "gcc-12-base:12.2.0-14" + } + ] + ] + }, + "deb://debian:bookworm:libgcc-s1:12.2.0-14": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libgcc-s1:12.2.0-14", + "full_path": "libgcc-s1:12.2.0-14" + } + ] + ] + }, + "deb://debian:bookworm:libstdc++6:12.2.0-14": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libstdc++6:12.2.0-14", + "full_path": "libstdc++6:12.2.0-14" + } + ] + ] + } + }, + "issue_id": "XRAY-531779", + "references": [ + "https://github.com/metaredteam/external-disclosures/security/advisories/GHSA-x7ch-h5rf-w2mf", + "https://developer.arm.com/Arm%20Security%20Center/GCC%20Stack%20Protector%20Vulnerability%20AArch64", + "https://security-tracker.debian.org/tracker/CVE-2023-4039" + ] + }, + { + "cves": [ + { + "cve": "CVE-2022-27943", + "cvss_v2_score": "4.3", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:N/A:P", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-674" + ], + "cwe_details": { + "CWE-674": { + "name": "Uncontrolled Recursion", + "description": "The product does not properly control the amount of recursion that takes place, consuming excessive resources, such as allocated memory or the program stack." + } + } + } + ], + "summary": "libiberty/rust-demangle.c in GNU GCC 11.2 allows stack consumption in demangle_const, as demonstrated by nm-new.", + "severity": "Low", + "components": { + "deb://debian:bookworm:gcc-12-base:12.2.0-14": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:gcc-12-base:12.2.0-14", + "full_path": "gcc-12-base:12.2.0-14" + } + ] + ] + }, + "deb://debian:bookworm:libgcc-s1:12.2.0-14": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libgcc-s1:12.2.0-14", + "full_path": "libgcc-s1:12.2.0-14" + } + ] + ] + }, + "deb://debian:bookworm:libstdc++6:12.2.0-14": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libstdc++6:12.2.0-14", + "full_path": "libstdc++6:12.2.0-14" + } + ] + ] + } + }, + "issue_id": "XRAY-203474", + "references": [ + "https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105039", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/H424YXGW7OKXS2NCAP35OP6Y4P4AW6VG/", + "https://security-tracker.debian.org/tracker/CVE-2022-27943", + "https://sourceware.org/bugzilla/show_bug.cgi?id=28995" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-28182" + } + ], + "summary": "nghttp2 is an implementation of the Hypertext Transfer Protocol version 2 in C. The nghttp2 library prior to version 1.61.0 keeps reading the unbounded number of HTTP/2 CONTINUATION frames even after a stream is reset to keep HPACK context in sync. This causes excessive CPU usage to decode HPACK stream. nghttp2 v1.61.0 mitigates this vulnerability by limiting the number of CONTINUATION frames it accepts per stream. There is no workaround for this vulnerability.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libnghttp2-14:1.52.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libnghttp2-14:1.52.0-1", + "full_path": "libnghttp2-14:1.52.0-1" + } + ] + ] + } + }, + "issue_id": "XRAY-597311", + "references": [ + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/J6ZMXUGB66VAXDW5J6QSTHM5ET25FGSA/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/PXJO2EASHM2OQQLGVDY5ZSO7UVDVHTDK/", + "https://github.com/nghttp2/nghttp2/commit/d71a4668c6bead55805d18810d633fbb98315af9", + "https://github.com/nghttp2/nghttp2/security/advisories/GHSA-x6x3-gv8h-m57q", + "https://github.com/nghttp2/nghttp2/commit/00201ecd8f982da3b67d4f6868af72a1b03b14e0", + "https://security-tracker.debian.org/tracker/CVE-2024-28182", + "https://lists.debian.org/debian-lts-announce/2024/04/msg00026.html", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/AGOME6ZXJG7664IPQNVE3DL67E3YP3HY/", + "http://www.openwall.com/lists/oss-security/2024/04/03/16" + ], + "extended_information": { + "short_description": "A design problem in the implementation of the HTTP/2 protocol in Nghttp2 may lead to denial of service by abusing frame flags.", + "full_description": "[Nghttp2](https://github.com/nghttp2/nghttp2) is an open-source implementation of HTTP/2, a significant upgrade to the HTTP protocol, offering improved efficiency and performance for web communication. It provides libraries and command-line tools for developers to integrate HTTP/2 features into their applications, including binary framing, header compression, multiplexing of requests, and server push. `Nghttp2` is widely used in various projects, such as web servers, proxies, and clients.\n\n`HTTP/2` is a binary protocol where the client and server exchange binary frames instead of text lines as in `HTTP/1.x`. `HTTP/2` resolves numerous concerns found in HTTP/1.1 by organizing each HTTP message into a series of HTTP/2 frames. These frames include frame type, length, flags, stream identifier (ID), and payload.\n\nThe `HEADERS` frame type allows sending HTTP headers of, both, request and response. The `HEADERS` frame contains many flags.\nThe `CONTINUATION` frame type is similar to the `HEADER` frame, but it has just one flag: `END_HEADERS`. When it is not set, the peer knows that more headers are coming in the following `CONTINUATION` frames.\n\nThis mechanism allows an attacker to send an `HTTP/2` stream with `CONTINUATION` frames, without setting the `END_HEADERS` flag in any of the frames. This can cause denial-of-service when sending an excessive number of these crafted frames due to caching all frames in memory.\n\nThe issue is exploitable by default due to `Nghttp2` being an `HTTP/2`-only implementation.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are either extremely common or nonexistent (always exploitable)", + "description": "Nghttp2 is vulnerable in its default configuration." + }, + { + "name": "The issue has a detailed technical explanation published, that can aid in exploit development", + "description": "A very detailed technical write-up has been published regarding the issue." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "This issue can lead to denial of service." + }, + { + "name": "The issue can be exploited by attackers over the network" + }, + { + "name": "The issue has multiple mentions in general media", + "description": "This issue is related to the well-covered attack \"HTTP/2 CONTINUATION Flood\"." + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-44487", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "NVD-CWE-noinfo" + ] + } + ], + "summary": "The HTTP/2 protocol allows a denial of service (server resource consumption) because request cancellation can reset many streams quickly, as exploited in the wild in August through October 2023.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libnghttp2-14:1.52.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libnghttp2-14:1.52.0-1", + "full_path": "libnghttp2-14:1.52.0-1" + } + ] + ] + } + }, + "issue_id": "XRAY-533236", + "references": [ + "https://www.debian.org/security/2023/dsa-5540", + "https://github.com/eclipse/jetty.project/issues/10679", + "https://github.com/caddyserver/caddy/releases/tag/v2.7.5", + "https://cloud.google.com/blog/products/identity-security/google-cloud-mitigated-largest-ddos-attack-peaking-above-398-million-rps/", + "https://lists.debian.org/debian-lts-announce/2023/11/msg00001.html", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/3N4NJ7FR4X4FPZUGNTQAPSTVB2HB2Y4A/", + "https://github.com/apache/tomcat/tree/main/java/org/apache/coyote/http2", + "https://news.ycombinator.com/item?id=37830998", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LNMZJCDHGLJJLXO4OXWJMTVQRNWOC7UL/", + "https://github.com/dotnet/core/blob/e4613450ea0da7fd2fc6b61dfb2c1c1dec1ce9ec/release-notes/6.0/6.0.23/6.0.23.md?plain=1#L73", + "https://lists.debian.org/debian-lts-announce/2023/10/msg00024.html", + "http://www.openwall.com/lists/oss-security/2023/10/13/4", + "https://access.redhat.com/security/cve/cve-2023-44487", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/ZLU6U2R2IC2K64NDPNMV55AUAO65MAF4/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/2MBEPPC36UBVOZZNAXFHKLFGSLCMN5LI/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/ZKQSIKIAT5TJ3WSLU3RDBQ35YX4GY4V3/", + "https://lists.apache.org/thread/5py8h42mxfsn8l1wy6o41xwhsjlsd87q", + "https://edg.io/lp/blog/resets-leaks-ddos-and-the-tale-of-a-hidden-cve", + "https://cgit.freebsd.org/ports/commit/?id=c64c329c2c1752f46b73e3e6ce9f4329be6629f9", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/KSEGD2IWKNUO3DWY4KQGUQM5BISRWHQE/", + "https://github.com/micrictor/http2-rst-stream", + "https://github.com/nghttp2/nghttp2/releases/tag/v1.57.0", + "http://www.openwall.com/lists/oss-security/2023/10/13/9", + "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-44487", + "https://bugzilla.proxmox.com/show_bug.cgi?id=4988", + "https://news.ycombinator.com/item?id=37830987", + "https://blog.vespa.ai/cve-2023-44487/", + "https://github.com/tempesta-tech/tempesta/issues/1986", + "https://groups.google.com/g/golang-announce/c/iNNxDTCjZvo", + "https://linkerd.io/2023/10/12/linkerd-cve-2023-44487/", + "https://github.com/kazu-yamamoto/http2/issues/93", + "https://github.com/Kong/kong/discussions/11741", + "https://www.cisa.gov/news-events/alerts/2023/10/10/http2-rapid-reset-vulnerability-cve-2023-44487", + "https://github.com/envoyproxy/envoy/pull/30055", + "https://lists.debian.org/debian-lts-announce/2023/10/msg00045.html", + "https://openssf.org/blog/2023/10/10/http-2-rapid-reset-vulnerability-highlights-need-for-rapid-response/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/FNA62Q767CFAFHBCDKYNPBMZWB7TWYVU/", + "https://lists.debian.org/debian-lts-announce/2023/10/msg00023.html", + "https://www.debian.org/security/2023/dsa-5558", + "https://blog.litespeedtech.com/2023/10/11/rapid-reset-http-2-vulnerablilty/", + "https://security.gentoo.org/glsa/202311-09", + "https://bugzilla.suse.com/show_bug.cgi?id=1216123", + "https://www.darkreading.com/cloud/internet-wide-zero-day-bug-fuels-largest-ever-ddos-event", + "https://github.com/projectcontour/contour/pull/5826", + "https://github.com/golang/go/issues/63417", + "https://github.com/netty/netty/commit/58f75f665aa81a8cbcf6ffa74820042a285c5e61", + "https://blog.cloudflare.com/zero-day-rapid-reset-http2-record-breaking-ddos-attack/", + "https://ubuntu.com/security/CVE-2023-44487", + "https://martinthomson.github.io/h2-stream-limits/draft-thomson-httpbis-h2-stream-limits.html", + "https://www.debian.org/security/2023/dsa-5521", + "https://www.debian.org/security/2023/dsa-5570", + "https://github.com/h2o/h2o/pull/3291", + "https://github.com/oqtane/oqtane.framework/discussions/3367", + "https://github.com/opensearch-project/data-prepper/issues/3474", + "https://github.com/advisories/GHSA-vx74-f528-fxqg", + "https://bugzilla.redhat.com/show_bug.cgi?id=2242803", + "https://github.com/etcd-io/etcd/issues/16740", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/CLB4TW7KALB3EEQWNWCN7OUIWWVWWCG2/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/BFQD3KUEMFBHPAPBGLWQC34L4OWL5HAZ/", + "https://github.com/icing/mod_h2/blob/0a864782af0a942aa2ad4ed960a6b32cd35bcf0a/mod_http2/README.md?plain=1#L239-L244", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LKYHSZQFDNR7RSA7LHVLLIAQMVYCUGBG/", + "https://github.com/apache/trafficserver/pull/10564", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/VSRDIV77HNKUSM7SJC5BKE5JSHLHU2NK/", + "https://lists.debian.org/debian-lts-announce/2023/10/msg00020.html", + "https://istio.io/latest/news/security/istio-security-2023-004/", + "https://news.ycombinator.com/item?id=37837043", + "https://security.netapp.com/advisory/ntap-20240621-0007/", + "https://discuss.hashicorp.com/t/hcsec-2023-32-vault-consul-and-boundary-affected-by-http-2-rapid-reset-denial-of-service-vulnerability-cve-2023-44487/59715", + "https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/", + "https://github.com/dotnet/announcements/issues/277", + "http://www.openwall.com/lists/oss-security/2023/10/20/8", + "https://github.com/kubernetes/kubernetes/pull/121120", + "https://security.paloaltonetworks.com/CVE-2023-44487", + "https://www.nginx.com/blog/http-2-rapid-reset-attack-impacting-f5-nginx-products/", + "https://www.theregister.com/2023/10/10/http2_rapid_reset_zeroday/", + "https://github.com/junkurihara/rust-rpxy/issues/97", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/JIZSEFC3YKCGABA2BZW6ZJRMDZJMB7PJ/", + "https://community.traefik.io/t/is-traefik-vulnerable-to-cve-2023-44487/20125", + "http://www.openwall.com/lists/oss-security/2023/10/18/4", + "https://lists.w3.org/Archives/Public/ietf-http-wg/2023OctDec/0025.html", + "https://github.com/facebook/proxygen/pull/466", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/X6QXN4ORIVF6XBW4WWFE7VNPVC74S45Y/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/VHUHTSXLXGXS7JYKBXTA3VINUPHTNGVU/", + "https://lists.debian.org/debian-lts-announce/2023/10/msg00047.html", + "https://lists.debian.org/debian-lts-announce/2023/11/msg00012.html", + "https://msrc.microsoft.com/blog/2023/10/microsoft-response-to-distributed-denial-of-service-ddos-attacks-against-http/2/", + "https://tomcat.apache.org/security-10.html#Fixed_in_Apache_Tomcat_10.1.14", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/ZB43REMKRQR62NJEI7I5NQ4FSXNLBKRT/", + "https://github.com/advisories/GHSA-qppj-fm5r-hxr3", + "https://aws.amazon.com/security/security-bulletins/AWS-2023-011/", + "https://blog.qualys.com/vulnerabilities-threat-research/2023/10/10/cve-2023-44487-http-2-rapid-reset-attack", + "https://cloud.google.com/blog/products/identity-security/how-it-works-the-novel-http2-rapid-reset-ddos-attack", + "https://news.ycombinator.com/item?id=37831062", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/E72T67UPDRXHIDLO3OROR25YAMN4GGW5/", + "https://github.com/alibaba/tengine/issues/1872", + "http://www.openwall.com/lists/oss-security/2023/10/18/8", + "https://github.com/advisories/GHSA-xpw8-rcwv-8f8p", + "https://github.com/microsoft/CBL-Mariner/pull/6381", + "https://www.debian.org/security/2023/dsa-5549", + "https://security.netapp.com/advisory/ntap-20240426-0007/", + "https://github.com/kazu-yamamoto/http2/commit/f61d41a502bd0f60eb24e1ce14edc7b6df6722a1", + "https://security.netapp.com/advisory/ntap-20240621-0006/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/HT7T2R4MQKLIF4ODV4BDLPARWFPCJ5CZ/", + "https://gist.github.com/adulau/7c2bfb8e9cdbe4b35a5e131c66a0c088", + "https://www.netlify.com/blog/netlify-successfully-mitigates-cve-2023-44487/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/XFOIBB4YFICHDM7IBOP7PWXW3FX4HLL2/", + "https://security.netapp.com/advisory/ntap-20231016-0001/", + "https://www.haproxy.com/blog/haproxy-is-not-affected-by-the-http-2-rapid-reset-attack-cve-2023-44487", + "https://github.com/nghttp2/nghttp2/pull/1961", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/JMEXY22BFG5Q64HQCM5CK2Q7KDKVV4TY/", + "https://github.com/apache/httpd-site/pull/10", + "https://my.f5.com/manage/s/article/K000137106", + "https://github.com/akka/akka-http/issues/4323", + "https://arstechnica.com/security/2023/10/how-ddosers-used-the-http-2-protocol-to-deliver-attacks-of-unprecedented-size/", + "https://github.com/arkrwn/PoC/tree/main/CVE-2023-44487", + "https://www.bleepingcomputer.com/news/security/new-http-2-rapid-reset-zero-day-attack-breaks-ddos-records/", + "https://github.com/line/armeria/pull/5232", + "https://security-tracker.debian.org/tracker/CVE-2023-44487", + "https://github.com/apache/httpd/blob/afcdbeebbff4b0c50ea26cdd16e178c0d1f24152/modules/http2/h2_mplx.c#L1101-L1113", + "https://www.openwall.com/lists/oss-security/2023/10/10/6", + "https://github.com/grpc/grpc-go/pull/6703", + "https://github.com/caddyserver/caddy/issues/5877", + "https://github.com/Azure/AKS/issues/3947", + "https://github.com/nodejs/node/pull/50121", + "https://github.com/haproxy/haproxy/issues/2312", + "https://github.com/ninenines/cowboy/issues/1615", + "http://www.openwall.com/lists/oss-security/2023/10/19/6", + "https://github.com/h2o/h2o/security/advisories/GHSA-2m7v-gc89-fjqf", + "https://mailman.nginx.org/pipermail/nginx-devel/2023-October/S36Q5HBXR7CAIMPLLPRSSSYR4PCMWILK.html", + "https://github.com/openresty/openresty/issues/930", + "https://github.com/bcdannyboy/CVE-2023-44487", + "https://forums.swift.org/t/swift-nio-http2-security-update-cve-2023-44487-http-2-dos/67764", + "https://github.com/linkerd/website/pull/1695/commits/4b9c6836471bc8270ab48aae6fd2181bc73fd632", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/WE2I52RHNNU42PX6NZ2RBUHSFFJ2LVZX/", + "https://www.debian.org/security/2023/dsa-5522", + "https://www.phoronix.com/news/HTTP2-Rapid-Reset-Attack", + "https://seanmonstar.com/post/730794151136935936/hyper-http2-rapid-reset-unaffected", + "https://netty.io/news/2023/10/10/4-1-100-Final.html", + "https://github.com/varnishcache/varnish-cache/issues/3996", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/WLPRQ5TWUQQXYWBJM7ECYDAIL2YVKIUH/", + "https://github.com/apache/apisix/issues/10320" + ], + "extended_information": { + "short_description": "A design problem in the implementation of the HTTP/2 protocol may lead to DoS and ease the possibility of DDoS in web server applications by abusing request cancellation.", + "full_description": "[The HTTP (Hypertext Transfer Protocol)](https://developer.mozilla.org/en-US/docs/Web/HTTP) is a fundamental protocol of the World Wide Web, enabling the exchange of data between a client (typically a web browser) and a server. It defines the rules for requesting and transmitting web pages and other resources over the internet. Request and response messages are exchanged as a stream of ASCII characters, sent over a reliable transport layer like TCP.\n\n[HTTP/2](https://http2.github.io/) is a modern network protocol designed to improve the performance and efficiency of web communication. It replaces the older HTTP/1.1 protocol and introduces features like header compression and enhanced request cancellation mechanisms, which collectively enhance the speed and responsiveness of websites.\n\nThis request cancellation mechanism allows clients to terminate unnecessary or redundant requests without waiting for a server's response, reducing network congestion and further improving the overall responsiveness of web applications.\n\nHTTP/2 resolves numerous concerns found in HTTP/1.1 by organizing each HTTP message into a series of HTTP/2 frames. These frames include type, length, flags, stream identifier (ID), and payload. The stream ID is essential in clearly associating specific bytes on the network with their corresponding messages, facilitating secure multiplexing and concurrent processing. These streams are bidirectional, enabling clients to transmit frames, and servers to respond with frames using the same ID.\n\nAs detailed in [this technical analysis](https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/), there's a vulnerability in the way request cancellation is implemented. The flaw lies in the process of sending an excessive number of requests (specifically, `HEADERS` frames), each immediately followed by a request cancellation frame utilizing the `RST_STREAM` frame. This sequence rapidly leads to a substantial consumption of server-side resources. Consequently, this vulnerability amplifies the risk of Distributed Denial of Service (DDoS) attacks, making it easier to overwhelm and exhaust the server's available resources.\n\nA lot of server applications are vulnerable to the Http/2 Rapid Reset attack.\nHowever, note that HTTP/2 must be enabled, which is not the default configuration on most applications (excluding nghttp2 for example).\nA non-exhaustive list of these vulnerable web applications:\n```\n- Tomcat\n- Jetty\n- NGINX on certain conditions\n- nghttp2\n- Netty\n```", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has been reported to be actively exploited in public networks", + "description": "Cloudflare identified this vulnerability being exploited in a DDoS attack of unprecedented scale on August 25, 2023, which surpassed their previous largest recorded attack by almost threefold." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker should attack a web server application with HTTP/2 protocol enabled and no (or a high) keepalive-requests options.", + "is_positive": true + }, + { + "name": "The issue can be exploited by attackers over the network" + }, + { + "name": "The issue has an exploit published", + "description": "A [PoC exists](https://github.com/imabee101/CVE-2023-44487) for this issue" + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "This issue can lead to DoS on popular server applications using HTTP/2 protocol and ease the possibility of DDoS attack." + }, + { + "name": "The issue has multiple mentions in general media", + "description": "The vulnerability received extensive media coverage from Google, Cloudflare, and more." + } + ], + "remediation": "##### Deployment mitigations\n\nA possible mitigation is to limit the maximum number of requests that can be made over a single keep-alive connection.\n\n##### Deployment mitigations\n\nFor NGINX:\n\nDisabling HTTP/2 in NGINX is not necessary. Simply ensure you have configured:\n\n- `keepalive_requests` should be kept at the default setting of 1000 requests\n- `http2_max_concurrent_streams` should be kept at the default setting of 128 streams\n- `limit_conn` and `limit_req` should be set \"with a reasonable setting balancing application performance and security\"\n\n##### Development mitigations\n\nFor Nghttp2:\nImplement `nghttp2_on_frame_recv_callback` callback function, and check and count `RST_STREAM` frames. If an excessive number of `RST_STREAM` frames are received, then take action, such as dropping the connection silently, or calling `nghttp2_submit_goaway` and gracefully terminate the connection.\n```c\n#include \u003cnghttp2/nghttp2.h\u003e\n\n// Callback function for handling frame reception\nint on_frame_recv_callback(nghttp2_session* session,\n const nghttp2_frame* frame, void* user_data) {\n // Check if the received frame is an RST_STREAM frame\n if (frame-\u003ehd.type == NGHTTP2_RST_STREAM) {\n // Increment a counter for RST_STREAM frames\n int* rst_stream_counter = (int*)user_data;\n (*rst_stream_counter)++;\n \n // Define a threshold for excessive RST_STREAM frames\n int rst_stream_threshold = 10; // Adjust this value as needed\n \n // If the threshold is exceeded, take action (e.g., close the connection)\n if (*rst_stream_counter \u003e rst_stream_threshold) {\n // Here, you can choose to close the connection gracefully or drop it\n // For demonstration purposes, we'll just print a message\n printf(\"Excessive RST_STREAM frames received. Closing the connection.\\n\");\n // You can call nghttp2_submit_goaway() to send a GOAWAY frame if needed.\n // nghttp2_submit_goaway(session, NGHTTP2_FLAG_NONE, error_code, opaque_data);\n // Then, close the connection.\n }\n }\n \n // Continue processing other frames if needed\n return 0;\n}\n\nint main() {\n // Initialize nghttp2_session and set up the on_frame_recv_callback\n nghttp2_session* session;\n int rst_stream_counter = 0;\n \n // Initialize nghttp2_session, set up callbacks, etc.\n // ...\n\n // Set the user data to be passed to the callback\n nghttp2_session_user_data(session, \u0026rst_stream_counter);\n \n // Register the on_frame_recv_callback\n nghttp2_session_callbacks* callbacks;\n nghttp2_session_callbacks_new(\u0026callbacks);\n nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks, on_frame_recv_callback);\n // Other callback registrations here...\n \n // Attach the callbacks to the session\n nghttp2_session_server_new(\u0026session, callbacks, \u0026rst_stream_counter);\n \n // Start processing HTTP/2 frames\n // ...\n\n // Cleanup and finish the program\n // ...\n\n return 0;\n}\n```\n\n##### Development mitigations\n\nFor Golang:\n\nThe default stream concurrency limit in `golang` is `250 streams (requests) per HTTP/2 connection`. This value may be adjusted in the `golang.org/x/net/http2` package using the `Server.MaxConcurrentStreams` setting and the `ConfigureServer` function which are available in `golang.org/x/net/http2`.\n\n```go\nimport (\n\t\"fmt\"\n\t\"golang.org/x/net/http2\"\n\t\"net/http\"\n)\n\nfunc main() {\n\t// Create an HTTP/2 server instance\n\thttp2Server := \u0026http2.Server{}\n\n\t// Set the desired stream concurrency limit\n\tmaxConcurrentStreams := 500 // Change this to your desired limit\n\thttp2Server.MaxConcurrentStreams = uint32(maxConcurrentStreams)\n\n\t// Configure an HTTP server to use HTTP/2 with the adjusted settings\n\tserver := \u0026http.Server{\n\t\tAddr: \":8080\",\n\t\tHandler: http.HandlerFunc(handleRequest),\n\t}\n\thttp2.ConfigureServer(server, http2Server)\n\n\t// Start the HTTP server\n\terr := server.ListenAndServeTLS(\"cert.pem\", \"key.pem\")\n\tif err != nil {\n\t\tfmt.Println(\"Error:\", err)\n\t}\n}\n```\n\n##### Development mitigations\n\nFor netty:\n```java\nimport io.netty.handler.codec.http2.Http2FrameListener;\nimport io.netty.handler.codec.http2.Http2FrameStream;\nimport io.netty.handler.codec.http2.Http2ResetFrame;\nimport io.netty.handler.codec.http2.Http2HeadersFrame;\n\npublic class CustomHttp2FrameListener implements Http2FrameListener {\n private int rstFrameCount = 0;\n private int maxRstFrameCount = 10; // Adjust this to your desired limit\n private long resetTimeMillis = System.currentTimeMillis();\n private long resetTimeIntervalMillis = 60000; // 60 seconds\n\n @Override\n public int onDataRead(Http2FrameStream stream, byte[] data, int padding, boolean endOfStream) {\n // Handle data frames if needed\n return 0;\n }\n\n @Override\n public void onHeadersRead(Http2FrameStream stream, Http2HeadersFrame headersFrame) {\n // Handle headers frames if needed\n }\n\n @Override\n public void onHeadersRead(Http2FrameStream stream, Http2HeadersFrame headersFrame, boolean endOfStream) {\n // Handle headers frames if needed\n }\n\n @Override\n public void onRstStreamRead(Http2FrameStream stream, Http2ResetFrame resetFrame) {\n long currentTimeMillis = System.currentTimeMillis();\n \n // Check if the reset time interval has passed, and reset the count if needed\n if (currentTimeMillis - resetTimeMillis \u003e= resetTimeIntervalMillis) {\n rstFrameCount = 0;\n resetTimeMillis = currentTimeMillis;\n }\n \n rstFrameCount++;\n \n // Check if the count exceeds the limit\n if (rstFrameCount \u003e maxRstFrameCount) {\n // Take action, e.g., close the connection, log, or drop frames\n // You can use stream or resetFrame to get more context if needed.\n // To close the connection, you can use stream.connection().close();\n }\n }\n}\n```" + } + }, + { + "cves": [ + { + "cve": "CVE-2023-45853", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-190" + ], + "cwe_details": { + "CWE-190": { + "name": "Integer Overflow or Wraparound", + "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "14" + } + ] + } + } + } + ], + "summary": "MiniZip in zlib through 1.3 has an integer overflow and resultant heap-based buffer overflow in zipOpenNewFileInZip4_64 via a long filename, comment, or extra field. NOTE: MiniZip is not a supported part of the zlib product. NOTE: pyminizip through 0.2.6 is also vulnerable because it bundles an affected zlib version, and exposes the applicable MiniZip code through its compress API.", + "severity": "Critical", + "components": { + "deb://debian:bookworm:zlib1g:1:1.2.13.dfsg-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:zlib1g:1:1.2.13.dfsg-1", + "full_path": "zlib1g:1:1.2.13.dfsg-1" + } + ] + ] + } + }, + "issue_id": "XRAY-533715", + "references": [ + "http://www.openwall.com/lists/oss-security/2024/01/24/10", + "http://www.openwall.com/lists/oss-security/2023/10/20/9", + "https://github.com/madler/zlib/blob/ac8f12c97d1afd9bafa9c710f827d40a407d3266/contrib/README.contrib#L1-L4", + "https://www.winimage.com/zLibDll/minizip.html", + "https://chromium.googlesource.com/chromium/src/+/de29dd6c7151d3cd37cb4cf0036800ddfb1d8b61", + "https://pypi.org/project/pyminizip/#history", + "https://lists.debian.org/debian-lts-announce/2023/11/msg00026.html", + "https://security.gentoo.org/glsa/202401-18", + "https://chromium.googlesource.com/chromium/src/+/d709fb23806858847131027da95ef4c548813356", + "https://github.com/madler/zlib/pull/843", + "https://security.netapp.com/advisory/ntap-20231130-0009/", + "https://security-tracker.debian.org/tracker/CVE-2023-45853" + ], + "extended_information": { + "short_description": "A heap buffer overflow in zlib may lead to remote code execution when parsing a malicious archive.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "PoC demonstrates a heap overflow that crashes the application. Although not demonstrated, it is likely that an RCE exploit could be developed, since zip-processing may allow many heap-shaping primitives needed for a full RCE exploit." + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "An attacker could compromise a server that is using the `zlib` library to zip or unzip any files." + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS score does not reflect the context-dependent nature of this vulnerability.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Remote code execution." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker must find a way to upload a crafted zip archive, that is subsequently processed by the vulnerable `zipOpenNewFileInZip4_64` function.", + "is_positive": true + } + ], + "remediation": "##### Development mitigations\n\nMake sure that files with names larger than 65536 characters are not parsed using `zlib`.\n\nAlso, a fix currently exists in the `develop` branch of `zlib` and can be deployed manually." + } + }, + { + "cves": [ + { + "cve": "CVE-2024-37371", + "cvss_v3_score": "9.1", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H", + "cwe": [ + "NVD-CWE-Other" + ] + } + ], + "summary": "In MIT Kerberos 5 (aka krb5) before 1.21.3, an attacker can cause invalid memory reads during GSS message token handling by sending message tokens with invalid length fields.", + "severity": "Critical", + "components": { + "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", + "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", + "full_path": "libk5crypto3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", + "full_path": "libkrb5-3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", + "full_path": "libkrb5support0:1.20.1-2+deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-607813", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-37371", + "https://web.mit.edu/kerberos/www/advisories/", + "https://github.com/krb5/krb5/commit/55fbf435edbe2e92dd8101669b1ce7144bc96fef" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-37370", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", + "cwe": [ + "NVD-CWE-noinfo" + ] + } + ], + "summary": "In MIT Kerberos 5 (aka krb5) before 1.21.3, an attacker can modify the plaintext Extra Count field of a confidential GSS krb5 wrap token, causing the unwrapped token to appear truncated to the application.", + "severity": "High", + "components": { + "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", + "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", + "full_path": "libk5crypto3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", + "full_path": "libkrb5-3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", + "full_path": "libkrb5support0:1.20.1-2+deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-607812", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-37370", + "https://web.mit.edu/kerberos/www/advisories/", + "https://github.com/krb5/krb5/commit/55fbf435edbe2e92dd8101669b1ce7144bc96fef" + ] + }, + { + "cves": [ + { + "cve": "CVE-2011-0283", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P", + "cwe": [ + "NVD-CWE-Other" + ] + } + ], + "summary": "The Key Distribution Center (KDC) in MIT Kerberos 5 (aka krb5) 1.9 allows remote attackers to cause a denial of service (NULL pointer dereference and daemon crash) via a malformed request packet that does not trigger a response packet.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", + "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", + "full_path": "libk5crypto3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", + "full_path": "libkrb5-3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", + "full_path": "libkrb5support0:1.20.1-2+deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-515010", + "references": [ + "http://web.mit.edu/kerberos/advisories/MITKRB5-SA-2011-002.txt", + "http://www.securityfocus.com/bid/46272", + "http://securityreason.com/securityalert/8073", + "http://www.vupen.com/english/advisories/2011/0330", + "http://secunia.com/advisories/43260", + "http://www.securitytracker.com/id?1025037", + "http://www.securityfocus.com/archive/1/516299/100/0/threaded", + "https://security-tracker.debian.org/tracker/CVE-2011-0283" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-26462" + } + ], + "summary": "Kerberos 5 (aka krb5) 1.21.2 contains a memory leak vulnerability in /krb5/src/kdc/ndr.c.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", + "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", + "full_path": "libk5crypto3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", + "full_path": "libkrb5-3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", + "full_path": "libkrb5support0:1.20.1-2+deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-592118", + "references": [ + "https://security.netapp.com/advisory/ntap-20240415-0012/", + "https://github.com/LuMingYinDetect/krb5_defects/blob/main/krb5_detect_3.md", + "https://security-tracker.debian.org/tracker/CVE-2024-26462" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-26458" + } + ], + "summary": "Kerberos 5 (aka krb5) 1.21.2 contains a memory leak in /krb5/src/lib/rpc/pmap_rmt.c.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", + "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", + "full_path": "libk5crypto3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", + "full_path": "libkrb5-3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", + "full_path": "libkrb5support0:1.20.1-2+deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-592120", + "references": [ + "https://github.com/LuMingYinDetect/krb5_defects/blob/main/krb5_detect_1.md", + "https://security-tracker.debian.org/tracker/CVE-2024-26458", + "https://security.netapp.com/advisory/ntap-20240415-0010/" + ] + }, + { + "cves": [ + { + "cve": "CVE-2018-5709", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:P/A:N", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", + "cwe": [ + "CWE-190" + ], + "cwe_details": { + "CWE-190": { + "name": "Integer Overflow or Wraparound", + "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "14" + } + ] + } + } + } + ], + "summary": "An issue was discovered in MIT Kerberos 5 (aka krb5) through 1.16. There is a variable \"dbentry-\u003en_key_data\" in kadmin/dbutil/dump.c that can store 16-bit data but unknowingly the developer has assigned a \"u4\" variable to it, which is for 32-bit data. An attacker can use this vulnerability to affect other artifacts of the database as we know that a Kerberos database dump file contains trusted data.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", + "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", + "full_path": "libk5crypto3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", + "full_path": "libkrb5-3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", + "full_path": "libkrb5support0:1.20.1-2+deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-60750", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2018-5709", + "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772%40%3Cdev.mina.apache.org%3E", + "https://github.com/poojamnit/Kerberos-V5-1.16-Vulnerabilities/tree/master/Integer%20Overflow" + ], + "extended_information": { + "short_description": "(Non-issue) Integer truncation in Kerberos5 leads to no impact when processing a crafted Kerberos5 beta7 format database file.", + "full_description": "[Kerberos](https://web.mit.edu/kerberos/) is a network authentication protocol. It is designed to provide strong authentication for client/server applications by using secret-key cryptography. A free implementation of this protocol is available from the Massachusetts Institute of Technology. Kerberos is available in many commercial products as well.\n\nA [Kerberos database](https://web.mit.edu/kerberos/krb5-1.12/doc/admin/database.html) contains all of a realm’s Kerberos principals, their passwords, and other administrative information about each principal. For the most part, you will use the `kdb5_util` program to manipulate the Kerberos database as a whole, and the `kadmin` program to make changes to the entries in the database. \n\nIn `kdb5_util`, there is a `process_k5beta7_princ` method responsible for adding Kerberos 5 beta 7 format data from a file to the Kerberos database. This function is vulnerable to integer overflow as a Database entry defined on 16-bits is assigned a 32-bits value from the given file. It turns out that it does not have any impact at all and it is not a security flaw.\n\nOriginally, the vulnerability was mistakenly reported as an Integer Overflow.\nThe issue should not affect any other data allocated close to the 16-bit integer in question. Furthermore, a negative value of the 16-bit integer does not impact the flow of the program in any meaningful way.\n\nTo trigger the integer truncation, an attacker has to get the user to use the `kdb5_util` utility to restore a Kerberos 5 - beta 7 format - database from a crafted malicious file. It can be done using the following command:\n```\nkdb5_util load -d DB_NAME DB_FILE \n```", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "Exploiting the issue requires the user to interact with the vulnerable software", + "description": "Requires the user to restore the Kerberos Database from a crafted malicious file, which is unlikely.", + "is_positive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "The integer truncation doesn't affect data allocated near the 16-bit integer and doesn't have any meaningful impact.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS does not reflect the fact that the vulnerability does not have any security impact.", + "is_positive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "A Kerberos database is not restored often. The attacker must find a way to get the user to restore the database from a crafted file. If the attacker has access to the backup file, it can be modified even without exploiting this vulnerability. The vulnerability only helps by making the attacker's modifications to the backup file seem legitimate when manually inspected.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2024-26461" + } + ], + "summary": "Kerberos 5 (aka krb5) 1.21.2 contains a memory leak vulnerability in /krb5/src/lib/gssapi/krb5/k5sealv3.c.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", + "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", + "full_path": "libk5crypto3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", + "full_path": "libkrb5-3:1.20.1-2+deb12u1" + } + ] + ] + }, + "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", + "full_path": "libkrb5support0:1.20.1-2+deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-592121", + "references": [ + "https://github.com/LuMingYinDetect/krb5_defects/blob/main/krb5_detect_2.md", + "https://security.netapp.com/advisory/ntap-20240415-0011/", + "https://security-tracker.debian.org/tracker/CVE-2024-26461" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-38950" + } + ], + "summary": "Heap Buffer Overflow vulnerability in Libde265 v1.0.15 allows attackers to crash the application via crafted payload to __interceptor_memcpy function.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "issue_id": "XRAY-607770", + "references": [ + "https://github.com/strukturag/libde265/issues/460", + "https://security-tracker.debian.org/tracker/CVE-2024-38950", + "https://github.com/zhangteng0526/CVE-information/blob/main/CVE-2024-38950" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-51792" + } + ], + "summary": "Buffer Overflow vulnerability in libde265 v1.0.12 allows a local attacker to cause a denial of service via the allocation size exceeding the maximum supported size of 0x10000000000.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "issue_id": "XRAY-599139", + "references": [ + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LE3ASLH6QF2E5OVJI5VA3JSEPJFFFMNY/", + "https://github.com/strukturag/libde265", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/IPETICRXUOGRIM4U3BCRTIKE3IZWCSBT/", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/6G7EYH2JAK5OJPVNC6AXYQ5K7YGYNCDN/", + "https://github.com/strukturag/libde265/issues/427", + "https://security-tracker.debian.org/tracker/CVE-2023-51792" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-49465", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "Libde265 v1.0.14 was discovered to contain a heap-buffer-overflow vulnerability in the derive_spatial_luma_vector_prediction function at motion.cc.", + "severity": "High", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "issue_id": "XRAY-540366", + "references": [ + "https://github.com/strukturag/libde265/issues/435", + "https://lists.debian.org/debian-lts-announce/2023/12/msg00022.html", + "https://security-tracker.debian.org/tracker/CVE-2023-49465" + ], + "extended_information": { + "short_description": "A non-proven heap buffer overflow in libde265 may lead to remote code execution when parsing attacker-supplied H.265 data.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "The attacker must be able to provide remote input that will be parsed by H.265, for example - `./dec265 attacker_input`.\nThe exploit only works on a small percent of executions, since the impact of parsing a malicious Atari DEGAS Elite bitmap file is contingent on the current heap state.", + "is_positive": true + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Although a PoC was linked to the issue, the maintainer was not able to reproduce the corruption. In addition, the heap buffer overflow was not proven to be able to cause remote code execution.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS does not take into account the non-trivial exploitation.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-43887", + "cvss_v3_score": "8.1", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H", + "cwe": [ + "CWE-120" + ], + "cwe_details": { + "CWE-120": { + "name": "Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')", + "description": "The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow." + } + } + } + ], + "summary": "Libde265 v1.0.12 was discovered to contain multiple buffer overflows via the num_tile_columns and num_tile_row parameters in the function pic_parameter_set::dump.", + "severity": "High", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "issue_id": "XRAY-538327", + "references": [ + "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html", + "https://security-tracker.debian.org/tracker/CVE-2023-43887", + "https://github.com/strukturag/libde265/issues/418", + "https://github.com/strukturag/libde265/commit/63b596c915977f038eafd7647d1db25488a8c133" + ], + "extended_information": { + "short_description": "An out of bounds read in libde265 may lead to denial of service or data leakage when decoding attacker-supplied data in a non-default configuration.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker has to be able to decode crafted H.265 files with the non-default dump headers option enabled. For example - `./dec265 -d attacker_input`", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "The Github issue has a linked PoC." + }, + { + "name": "The issue has a detailed technical explanation published, that can aid in exploit development", + "description": "The Github issue carefully explains the vulnerability." + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-27103", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "Libde265 v1.0.11 was discovered to contain a heap buffer overflow via the function derive_collocated_motion_vectors at motion.cc.", + "severity": "High", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "issue_id": "XRAY-427848", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-27103", + "https://github.com/strukturag/libde265/issues/394", + "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-47471", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-120" + ], + "cwe_details": { + "CWE-120": { + "name": "Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')", + "description": "The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow." + } + } + } + ], + "summary": "Buffer Overflow vulnerability in strukturag libde265 v1.10.12 allows a local attacker to cause a denial of service via the slice_segment_header function in the slice.cc component.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "issue_id": "XRAY-537162", + "references": [ + "https://github.com/strukturag/libde265/commit/e36b4a1b0bafa53df47514c419d5be3e8916ebc7", + "https://security-tracker.debian.org/tracker/CVE-2023-47471", + "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html", + "https://github.com/strukturag/libde265/issues/426" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-27102", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-476" + ], + "cwe_details": { + "CWE-476": { + "name": "NULL Pointer Dereference", + "description": "A NULL pointer dereference occurs when the application dereferences a pointer that it expects to be valid, but is NULL, typically causing a crash or exit.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "12" + } + ] + } + } + } + ], + "summary": "Libde265 v1.0.11 was discovered to contain a segmentation violation via the function decoder_context::process_slice_segment_header at decctx.cc.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "issue_id": "XRAY-427847", + "references": [ + "https://github.com/strukturag/libde265/issues/393", + "https://security-tracker.debian.org/tracker/CVE-2023-27102", + "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-49468", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "Libde265 v1.0.14 was discovered to contain a global buffer overflow vulnerability in the read_coding_unit function at slice.cc.", + "severity": "High", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "issue_id": "XRAY-540358", + "references": [ + "https://lists.debian.org/debian-lts-announce/2023/12/msg00022.html", + "https://security-tracker.debian.org/tracker/CVE-2023-49468", + "https://github.com/strukturag/libde265/issues/432" + ], + "extended_information": { + "short_description": "A buffer overflow (in a global variable) in libde265 causes memory corruption leading to DoS and possibly code execution, when parsing attacker-supplied H.265 data.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "The provided PoC demonstrates a crash." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must be able to provide remote input that will be parsed by H.265, for example - `./dec265 attacker_input`.", + "is_positive": true + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "The impact of this vulnerability depends on the implementation of the vulnerable library. Substantial research has to be conducted to determine the exact impact this vulnerability could have. Code execution is not always achievable through a buffer overflow in a global variable.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-49467", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "Libde265 v1.0.14 was discovered to contain a heap-buffer-overflow vulnerability in the derive_combined_bipredictive_merging_candidates function at motion.cc.", + "severity": "High", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "issue_id": "XRAY-540357", + "references": [ + "https://github.com/strukturag/libde265/issues/434", + "https://security-tracker.debian.org/tracker/CVE-2023-49467", + "https://lists.debian.org/debian-lts-announce/2023/12/msg00022.html" + ], + "extended_information": { + "short_description": "An infinite loop in libde265 leads to DoS when parsing attacker-supplied H.265 data.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS does not take into account the non-trivial exploitation prerequisites. In addition, the CVSS alludes that remote code execution is possible, while in reality the worst impact of exploiting this issue is denial of service.", + "is_positive": true + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "The attacker must be able to provide remote input that will be parsed by H.265, for example - `./dec265 attacker_input`.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2024-38949" + } + ], + "summary": "Heap Buffer Overflow vulnerability in Libde265 v1.0.15 allows attackers to crash the application via crafted payload to display444as420 function at sdl.cc", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libde265-0:1.0.11-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", + "full_path": "libde265-0:1.0.11-1" + } + ] + ] + } + }, + "issue_id": "XRAY-607769", + "references": [ + "https://github.com/strukturag/libde265/issues/460", + "https://github.com/zhangteng0526/CVE-information/blob/main/CVE-2024-38949", + "https://security-tracker.debian.org/tracker/CVE-2024-38949" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-6246", + "cvss_v3_score": "7.8", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "A heap-based buffer overflow was found in the __vsyslog_internal function of the glibc library. This function is called by the syslog and vsyslog functions. This issue occurs when the openlog function was not called, or called with the ident argument set to NULL, and the program name (the basename of argv[0]) is bigger than 1024 bytes, resulting in an application crash or local privilege escalation. This issue affects glibc 2.36 and newer.", + "severity": "High", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-589627", + "references": [ + "https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D2FIH77VHY3KCRROCXOT6L27WMZXSJ2G/", + "https://security.netapp.com/advisory/ntap-20240216-0007/", + "https://security-tracker.debian.org/tracker/CVE-2023-6246", + "https://access.redhat.com/security/cve/CVE-2023-6246", + "http://packetstormsecurity.com/files/176931/glibc-qsort-Out-Of-Bounds-Read-Write.html", + "http://seclists.org/fulldisclosure/2024/Feb/5", + "https://www.openwall.com/lists/oss-security/2024/01/30/6", + "http://packetstormsecurity.com/files/176932/glibc-syslog-Heap-Based-Buffer-Overflow.html", + "https://bugzilla.redhat.com/show_bug.cgi?id=2249053", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MWQ6BZJ6CV5UAW4VZSKJ6TO4KIW2KWAQ/", + "https://security.gentoo.org/glsa/202402-01", + "http://seclists.org/fulldisclosure/2024/Feb/3" + ], + "extended_information": { + "short_description": "A heap buffer overflow in glibc may lead to local privilege escalation.", + "full_description": "[glibc](https://www.gnu.org/software/libc/) is the GNU C Library, a widely-used implementation of the C standard library.\n\nA vulnerability was identified in __vsyslog_internal(), which is called by the API functions `syslog()` and `vsyslog()` of glibc syslog functionality. Unprivileged users could gain full root access by manipulating syslog inputs.\n\nThe initial prerequisite for exploiting this local privilege escalation is a local SUID executable that contains calls to one of the vulnerable functions `syslog()` and `vsyslog()`. In order to exploit this, the attacker needs to control either argv[0], which typically holds the name of the program being executed, or the `openlog()` ident argument. \n\nAs explained in [Qualys’s research](https://qualys.com/2024/01/30/cve-2023-6246/syslog.txt), the identification string (LogTag) being NULL is essential for exploiting this issue. Thus, the `openlog()` function would need to either not be called, or called with NULL for the ident param for successful exploitation. \n\nIn Qualys’s research, they utilized a code path in the `su` program that doesn’t reach `openlog()`. Meaning the default user-controlled, argv[0] was used. Keep in mind another attack vector is possible in a different scenario when the user can control the ident arg of `openlog()`.\n\nSeeing as argv[0] is the name (path) of the running program, it is highly likely for a local attacker to be able to abuse this CVE for a local privilege escalation and unlikely that a remote attacker will have control over this argument for an RCE attack.\n\nQualys demonstrated a successful LPE exploit on Fedora. While no other public exploits are yet known, the threat landscape could evolve. It is likely possible to exploit this on other Linux distributions as well.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has multiple mentions in general media", + "description": "The vulnerability received extensive media coverage." + }, + { + "name": "The issue has a detailed technical explanation published, that can aid in exploit development", + "description": "This vulnerability has a through technical writeup, which also details an exploit." + }, + { + "name": "The prerequisites for exploiting the issue are either extremely common or nonexistent (always exploitable)", + "description": "As explained in the summary, the requirements to trigger the vulnerability are highly likely on default Linux machines that use a vulnerable version of glibc." + }, + { + "name": "The issue can only be exploited by an attacker that can execute code on the vulnerable machine (excluding exceedingly rare circumstances)", + "description": "This vulnerability requires local access to exploit. It is unlikely to be exploitable in remote scenarios as explained in the summary.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "This is a local privilege escalation vulnerability that could enable a local attacker to execute code as a root user." + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2019-9192", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-674" + ], + "cwe_details": { + "CWE-674": { + "name": "Uncontrolled Recursion", + "description": "The product does not properly control the amount of recursion that takes place, consuming excessive resources, such as allocated memory or the program stack." + } + } + } + ], + "summary": "In the GNU C Library (aka glibc or libc6) through 2.29, check_dst_limits_calc_pos_1 in posix/regexec.c has Uncontrolled Recursion, as demonstrated by '(|)(\\\\1\\\\1)*' in grep, a different issue than CVE-2018-20796. NOTE: the software maintainer disputes that this is a vulnerability because the behavior occurs only with a crafted pattern", + "severity": "Low", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-75770", + "references": [ + "https://sourceware.org/bugzilla/show_bug.cgi?id=24269", + "https://support.f5.com/csp/article/K26346590?utm_source=f5support\u0026amp%3Butm_medium=RSS", + "https://security-tracker.debian.org/tracker/CVE-2019-9192" + ], + "extended_information": { + "short_description": "Uncontrolled recursion in glibc regexec leads to denial of service.", + "full_description": "The [GNU C Library](https://www.gnu.org/software/libc/), commonly known as glibc, is the GNU Project's implementation of the C standard library.\n\nIn the GNU C Library (aka glibc or libc6) through 2.29, `check_dst_limits_calc_pos_1` in posix/regexec.c has Uncontrolled Recursion, as demonstrated by running grep with the pattern `(|)(\\\\1\\\\1)*`.\n\nNote that in order to exploit this vulnerability, the attacker must control the regular expression **pattern** that glibc uses, unlike standard ReDoS vulnerabilities where only the input buffer needs to be controlled. The The pattern it not likely to be attacker-controlled from remote input.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must find a remote input that propagates to the `regex` (pattern) argument of `regcomp` and then sent to `regexec`.\nThis includes controlling the pattern argument of a `grep` invocation.", + "is_positive": true + }, + { + "name": "The issue has been disputed by the vendor", + "description": "The software maintainer disputes that this is not a vulnerability because the behavior occurs only with a crafted pattern. Therefore - this issue is unlikely to get a fix.", + "is_positive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "It is highly unlikely that a remote attacker will be able to control a regular expression pattern that's used by glibc", + "is_positive": true + }, + { + "name": "The issue has an exploit published" + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Denial of service only, marked as unimportant by the Debian tracker", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-6779", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "An off-by-one heap-based buffer overflow was found in the __vsyslog_internal function of the glibc library. This function is called by the syslog and vsyslog functions. This issue occurs when these functions are called with a message bigger than INT_MAX bytes, leading to an incorrect calculation of the buffer size to store the message, resulting in an application crash. This issue affects glibc 2.37 and newer.", + "severity": "High", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-589629", + "references": [ + "http://seclists.org/fulldisclosure/2024/Feb/3", + "https://security.netapp.com/advisory/ntap-20240223-0006/", + "https://access.redhat.com/security/cve/CVE-2023-6779", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D2FIH77VHY3KCRROCXOT6L27WMZXSJ2G/", + "https://security-tracker.debian.org/tracker/CVE-2023-6779", + "https://www.openwall.com/lists/oss-security/2024/01/30/6", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MWQ6BZJ6CV5UAW4VZSKJ6TO4KIW2KWAQ/", + "https://bugzilla.redhat.com/show_bug.cgi?id=2254395", + "https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt", + "https://security.gentoo.org/glsa/202402-01", + "http://packetstormsecurity.com/files/176932/glibc-syslog-Heap-Based-Buffer-Overflow.html" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-6780", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "cwe": [ + "CWE-131" + ], + "cwe_details": { + "CWE-131": { + "name": "Incorrect Calculation of Buffer Size", + "description": "The product does not correctly calculate the size to be used when allocating a buffer, which could lead to a buffer overflow." + } + } + } + ], + "summary": "An integer overflow was found in the __vsyslog_internal function of the glibc library. This function is called by the syslog and vsyslog functions. This issue occurs when these functions are called with a very long message, leading to an incorrect calculation of the buffer size to store the message, resulting in undefined behavior. This issue affects glibc 2.37 and newer.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-589628", + "references": [ + "http://seclists.org/fulldisclosure/2024/Feb/3", + "https://security.gentoo.org/glsa/202402-01", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MWQ6BZJ6CV5UAW4VZSKJ6TO4KIW2KWAQ/", + "https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D2FIH77VHY3KCRROCXOT6L27WMZXSJ2G/", + "http://packetstormsecurity.com/files/176932/glibc-syslog-Heap-Based-Buffer-Overflow.html", + "https://www.openwall.com/lists/oss-security/2024/01/30/6", + "https://access.redhat.com/security/cve/CVE-2023-6780", + "https://security-tracker.debian.org/tracker/CVE-2023-6780", + "https://bugzilla.redhat.com/show_bug.cgi?id=2254396" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-33601" + } + ], + "summary": "nscd: netgroup cache may terminate daemon on memory allocation failure\n\nThe Name Service Cache Daemon's (nscd) netgroup cache uses xmalloc or\nxrealloc and these functions may terminate the process due to a memory\nallocation failure resulting in a denial of service to the clients. The\nflaw was introduced in glibc 2.15 when the cache was added to nscd.\n\nThis vulnerability is only present in the nscd binary.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-599389", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-33601", + "https://sourceware.org/git/?p=glibc.git;a=blob;f=advisories/GLIBC-SA-2024-0007", + "https://lists.debian.org/debian-lts-announce/2024/06/msg00026.html", + "http://www.openwall.com/lists/oss-security/2024/07/22/5", + "https://security.netapp.com/advisory/ntap-20240524-0014/" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-33599" + } + ], + "summary": "nscd: Stack-based buffer overflow in netgroup cache\n\nIf the Name Service Cache Daemon's (nscd) fixed size cache is exhausted\nby client requests then a subsequent client request for netgroup data\nmay result in a stack-based buffer overflow. This flaw was introduced\nin glibc 2.15 when the cache was added to nscd.\n\nThis vulnerability is only present in the nscd binary.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-599387", + "references": [ + "http://www.openwall.com/lists/oss-security/2024/07/22/5", + "https://security-tracker.debian.org/tracker/CVE-2024-33599", + "https://lists.debian.org/debian-lts-announce/2024/06/msg00026.html", + "https://security.netapp.com/advisory/ntap-20240524-0011/", + "https://sourceware.org/git/?p=glibc.git;a=blob;f=advisories/GLIBC-SA-2024-0005" + ], + "extended_information": { + "short_description": "A stack buffer overflow in the Name Service Cache Daemon (NSCD) in the GNU C library may lead to remote code execution.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "No PoC and no technical writeup were published.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The `/etc/nscd.conf` configuration file does not support netgroup caching by default.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Potential remote code execution." + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "The Name Service Cache Daemon accepts arbitrary network input." + } + ], + "remediation": "##### Deployment mitigations\n\nDisable netgroup caching in the NSCD configuration.\nRemove the following line from `/etc/nscd.conf` -\n```\nenable-cache netgroup yes\n```" + } + }, + { + "cves": [ + { + "cve": "CVE-2019-1010022", + "cvss_v2_score": "7.5", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-119" + ], + "cwe_details": { + "CWE-119": { + "name": "Improper Restriction of Operations within the Bounds of a Memory Buffer", + "description": "The product performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "17" + } + ] + } + } + } + ], + "summary": "GNU Libc current is affected by: Mitigation bypass. The impact is: Attacker may bypass stack guard protection. The component is: nptl. The attack vector is: Exploit stack buffer overflow vulnerability and use this bypass vulnerability to bypass stack guard. NOTE: Upstream comments indicate \"this is being treated as a non-security bug and no real threat.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-84860", + "references": [ + "https://sourceware.org/bugzilla/show_bug.cgi?id=22850#c3", + "https://security-tracker.debian.org/tracker/CVE-2019-1010022", + "https://ubuntu.com/security/CVE-2019-1010022", + "https://sourceware.org/bugzilla/show_bug.cgi?id=22850" + ], + "extended_information": { + "short_description": "Insufficient mitigation implementation in glibc's pthread could lead to an attacker bypassing the stack protector/canary mitigation.", + "full_description": "The [GNU C Library](https://www.gnu.org/s/libc/), commonly known as glibc, is the GNU Project's implementation of the C standard library.\n\nA well-known issue leads to the fact that in applications that call `pthread_create()`, if a large stack buffer overflow occurs, the stack overflow may overwrite both the reference value of the stack canary and the canary that's saved inside the stack-frame. This leads to a complete bypass of the \"stack protector\" mitigation.\n\nSpecifically, The stack protector (\"canary\") should protect an application from been exploited by stack-based buffer overflows. It is placed on stack frame in function prologue and checked with some trusted value in the function epilogue.\n\nFor x86 and x86-64 architecture the canary value is located in structure `tcbhead_t` field `stack_guard`. A Special register ('gs' for i386 and 'fs' for x86-64) keeps a pointer to this structure. The value `tcbhead_t.stack_guard` is compared with one on the stack to detect stack smashing.\n\nNPTL (Native POSIX Threads Library) is the GNU C library POSIX threads implementation that is used on modern Linux systems. When a `pthread` (new thread) is created, it will keep the `tcphead_t` structure in the thread stack. Thus, an attacker can overwrite the \"reference\" stack-canary value (since it's saved on the stack) by means of stack overflow in a new thread.\n\nThis vulnerability was disputed by the libc maintainers, since it is a well-known issue and not a standalone vulnerability but rather a vulnerability in a mitigation mechanism.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "The PoC demonstrates changing the \"retained\" stack-canary value" + }, + { + "name": "The issue cannot be exploited on its own, and can only be used as part of an attack chain", + "description": "Exploitation of this issue requires exploiting a different stack-buffer-overflow vulnerability in the target application", + "is_positive": true + }, + { + "name": "The issue has been disputed by the vendor", + "description": "The Libc maintainers treat this issue as a non-security bug, since it is a vulnerability in a post-attack mitigation (not a standalone vulnerability)", + "is_positive": true + }, + { + "name": "The issue has a detailed technical explanation published, that can aid in exploit development" + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The victim application must call `pthread_create()` and must be vulnerable to a stack-buffer-overflow type of vulnerability", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2024-33602" + } + ], + "summary": "nscd: netgroup cache assumes NSS callback uses in-buffer strings\n\nThe Name Service Cache Daemon's (nscd) netgroup cache can corrupt memory\nwhen the NSS callback does not store all strings in the provided buffer.\nThe flaw was introduced in glibc 2.15 when the cache was added to nscd.\n\nThis vulnerability is only present in the nscd binary.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-599390", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-33602", + "http://www.openwall.com/lists/oss-security/2024/07/22/5", + "https://sourceware.org/git/?p=glibc.git;a=blob;f=advisories/GLIBC-SA-2024-0008", + "https://security.netapp.com/advisory/ntap-20240524-0012/", + "https://lists.debian.org/debian-lts-announce/2024/06/msg00026.html" + ] + }, + { + "cves": [ + { + "cve": "CVE-2019-1010025", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:N/A:N", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", + "cwe": [ + "CWE-330" + ], + "cwe_details": { + "CWE-330": { + "name": "Use of Insufficiently Random Values", + "description": "The product uses insufficiently random numbers or values in a security context that depends on unpredictable numbers." + } + } + } + ], + "summary": "GNU Libc current is affected by: Mitigation bypass. The impact is: Attacker may guess the heap addresses of pthread_created thread. The component is: glibc. NOTE: the vendor's position is \"ASLR bypass itself is not a vulnerability.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-84867", + "references": [ + "https://sourceware.org/bugzilla/show_bug.cgi?id=22853", + "https://support.f5.com/csp/article/K06046097", + "https://ubuntu.com/security/CVE-2019-1010025", + "https://support.f5.com/csp/article/K06046097?utm_source=f5support\u0026amp%3Butm_medium=RSS", + "https://security-tracker.debian.org/tracker/CVE-2019-1010025" + ] + }, + { + "cves": [ + { + "cve": "CVE-2019-1010023", + "cvss_v2_score": "6.8", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:P/I:P/A:P", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", + "cwe": [ + "NVD-CWE-noinfo" + ] + } + ], + "summary": "GNU Libc current is affected by: Re-mapping current loaded library with malicious ELF file. The impact is: In worst case attacker may evaluate privileges. The component is: libld. The attack vector is: Attacker sends 2 ELF files to victim and asks to run ldd on it. ldd execute code. NOTE: Upstream comments indicate \"this is being treated as a non-security bug and no real threat.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-84853", + "references": [ + "http://www.securityfocus.com/bid/109167", + "https://support.f5.com/csp/article/K11932200?utm_source=f5support\u0026amp%3Butm_medium=RSS", + "https://security-tracker.debian.org/tracker/CVE-2019-1010023", + "https://sourceware.org/bugzilla/show_bug.cgi?id=22851", + "https://ubuntu.com/security/CVE-2019-1010023" + ] + }, + { + "cves": [ + { + "cve": "CVE-2018-20796", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-674" + ], + "cwe_details": { + "CWE-674": { + "name": "Uncontrolled Recursion", + "description": "The product does not properly control the amount of recursion that takes place, consuming excessive resources, such as allocated memory or the program stack." + } + } + } + ], + "summary": "In the GNU C Library (aka glibc or libc6) through 2.29, check_dst_limits_calc_pos_1 in posix/regexec.c has Uncontrolled Recursion, as demonstrated by '(\\227|)(\\\\1\\\\1|t1|\\\\\\2537)+' in grep.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-75786", + "references": [ + "https://security.netapp.com/advisory/ntap-20190315-0002/", + "https://lists.gnu.org/archive/html/bug-gnulib/2019-01/msg00108.html", + "http://www.securityfocus.com/bid/107160", + "https://security-tracker.debian.org/tracker/CVE-2018-20796", + "https://support.f5.com/csp/article/K26346590?utm_source=f5support\u0026amp%3Butm_medium=RSS", + "https://debbugs.gnu.org/cgi/bugreport.cgi?bug=34141" + ], + "extended_information": { + "short_description": "An uncontrolled recursion in glibc may result in a denial of service via malformed regular expression.", + "full_description": "The [GNU C Library](https://www.gnu.org/software/libc/), commonly known as glibc, is the GNU Project's implementation of the C standard library.\n\nAn uncontrolled recursion vulnerability exists in glibc's regular expression parsing engine (posix/regexec.c).\n\nAn attacker can exploit this issue by invoking any tool (`grep`, `sed` etc.) or API (`regexec()`) with a crafted regular expression. This can be demonstrated by the crafted input: `(\\227|)(\\\\1\\\\1|t1|\\\\\\2537)+'`.\nThis scenario is much more likely in a local attack than a remote one.\n\nNote that in order to exploit this vulnerability, the attacker must control the regular expression **pattern** that glibc uses, unlike standard ReDoS vulnerabilities where only the input buffer needs to be controlled. The The pattern it not likely to be attacker-controlled from remote input.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has been disputed by the vendor", + "description": "The software maintainer disputes that this is not a vulnerability because the behavior occurs only with a crafted pattern. Therefore - this issue is unlikely to get a fix.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must find a remote input that propagates to the `regex` (pattern) argument of `regcomp` and then sent to `regexec`.\nThis includes controlling the pattern argument of a `grep` invocation.", + "is_positive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "It is highly unlikely that a remote attacker will be able to control a regular expression pattern that's used by glibc", + "is_positive": true + }, + { + "name": "The issue has an exploit published" + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Denial of service only, marked as unimportant by the Debian tracker", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2010-4756", + "cvss_v2_score": "4.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:S/C:N/I:N/A:P", + "cwe": [ + "CWE-399" + ] + } + ], + "summary": "The glob implementation in the GNU C Library (aka glibc or libc6) allows remote authenticated users to cause a denial of service (CPU and memory consumption) via crafted glob expressions that do not match any pathnames, as demonstrated by glob expressions in STAT commands to an FTP daemon, a different vulnerability than CVE-2010-2632.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-33571", + "references": [ + "http://securityreason.com/achievement_securityalert/89", + "https://security-tracker.debian.org/tracker/CVE-2010-4756", + "https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2010-4756", + "http://cxib.net/stuff/glob-0day.c", + "https://bugzilla.redhat.com/show_bug.cgi?id=681681", + "http://securityreason.com/exploitalert/9223" + ], + "extended_information": { + "short_description": "An unbounded computation in glibc leads to denial of service when parsing crafted glob expressions.", + "full_description": "The GNU C Library project provides the core libraries for the GNU system and GNU/Linux systems, as well as many other systems that use Linux as the kernel. One of the provided functions is `glob`. *This function expands a filename wildcard which is passed as pattern*. It usually implements a limitation though the `GLOB_LIMIT` constant but a flaw is causing a `denial of service when the crafted glob expression does not match any pathnames`.\nThis vulnerability is very similar to the one affecting the *STAT* commands against an FTP Deamon which gives information about the file and the filesystem, also vulnerable to glob expression causing the process to use 100% of the CPU capabilities for a long time.\nHowever, this vulnerability needs the attacker to be an authenticated user.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "It is unlikely that a remote attacker will be able to control a glob pattern from a remote input", + "is_positive": true + }, + { + "name": "The issue has been disputed by the vendor", + "description": "The software maintainer disputes that this is not a vulnerability because the behavior occurs only with a crafted glob pattern. Therefore - this issue is unlikely to get a fix.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker must find a remote input that propagates into the `pattern` argument of a `glob` call.\nHowever, as the technical [write-up](https://cxsecurity.com/issue/WLB-2010100135) shows, this vulnerability can be remotely exploited in some common cases, such as FTP servers.", + "is_positive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Marked as unimportant by the Debian tracker. Computation-based DoS.", + "is_positive": true + }, + { + "name": "The issue has a detailed technical explanation published, that can aid in exploit development", + "description": "A technical [write-up](https://cxsecurity.com/issue/WLB-2010100135) was published explaining the bug and how to trigger it." + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2019-1010024", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:N/A:N", + "cvss_v3_score": "5.3", + "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", + "cwe": [ + "CWE-200" + ], + "cwe_details": { + "CWE-200": { + "name": "Exposure of Sensitive Information to an Unauthorized Actor", + "description": "The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information." + } + } + } + ], + "summary": "GNU Libc current is affected by: Mitigation bypass. The impact is: Attacker may bypass ASLR using cache of thread stack and heap. The component is: glibc. NOTE: Upstream comments indicate \"this is being treated as a non-security bug and no real threat.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-84852", + "references": [ + "https://ubuntu.com/security/CVE-2019-1010024", + "https://support.f5.com/csp/article/K06046097?utm_source=f5support\u0026amp%3Butm_medium=RSS", + "https://security-tracker.debian.org/tracker/CVE-2019-1010024", + "https://sourceware.org/bugzilla/show_bug.cgi?id=22852", + "http://www.securityfocus.com/bid/109162", + "https://support.f5.com/csp/article/K06046097" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-33600" + } + ], + "summary": "nscd: Null pointer crashes after notfound response\n\nIf the Name Service Cache Daemon's (nscd) cache fails to add a not-found\nnetgroup response to the cache, the client request can result in a null\npointer dereference. This flaw was introduced in glibc 2.15 when the\ncache was added to nscd.\n\nThis vulnerability is only present in the nscd binary.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-599388", + "references": [ + "https://security.netapp.com/advisory/ntap-20240524-0013/", + "https://security-tracker.debian.org/tracker/CVE-2024-33600", + "https://lists.debian.org/debian-lts-announce/2024/06/msg00026.html", + "https://sourceware.org/git/?p=glibc.git;a=blob;f=advisories/GLIBC-SA-2024-0006", + "http://www.openwall.com/lists/oss-security/2024/07/22/5" + ], + "extended_information": { + "short_description": "A null pointer dereference in the Name Service Cache Daemon (NSCD) in the GNU C library may lead to denial of service.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "No PoC and no technical writeup were published.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The `/etc/nscd.conf` configuration file does not support netgroup caching by default.", + "is_positive": true + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "The Name Service Cache Daemon accepts arbitrary network input" + } + ], + "remediation": "##### Deployment mitigations\n\nDisable netgroup caching in the NSCD configuration.\nRemove the following line from `/etc/nscd.conf` -\n```\nenable-cache netgroup yes\n```" + } + }, + { + "cves": [ + { + "cve": "CVE-2024-2961" + } + ], + "summary": "The iconv() function in the GNU C Library versions 2.39 and older may overflow the output buffer passed to it by up to 4 bytes when converting strings to the ISO-2022-CN-EXT character set, which may be used to crash an application or overwrite a neighbouring variable.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", + "full_path": "libc-bin:2.36-9+deb12u3" + } + ] + ] + }, + "deb://debian:bookworm:libc6:2.36-9+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", + "full_path": "libc6:2.36-9+deb12u3" + } + ] + ] + } + }, + "issue_id": "XRAY-598749", + "references": [ + "https://lists.debian.org/debian-lts-announce/2024/05/msg00001.html", + "http://www.openwall.com/lists/oss-security/2024/07/22/5", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/YAMJQI3Y6BHWV3CUTYBXOZONCUJNOB2Z/", + "http://www.openwall.com/lists/oss-security/2024/04/24/2", + "https://security.netapp.com/advisory/ntap-20240531-0002/", + "http://www.openwall.com/lists/oss-security/2024/05/27/1", + "http://www.openwall.com/lists/oss-security/2024/05/27/3", + "https://sourceware.org/git/?p=glibc.git;a=blob;f=advisories/GLIBC-SA-2024-0004", + "http://www.openwall.com/lists/oss-security/2024/04/17/9", + "http://www.openwall.com/lists/oss-security/2024/05/27/5", + "http://www.openwall.com/lists/oss-security/2024/05/27/2", + "http://www.openwall.com/lists/oss-security/2024/05/27/4", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/BTJFBGHDYG5PEIFD5WSSSKSFZ2AZWC5N/", + "https://security-tracker.debian.org/tracker/CVE-2024-2961", + "http://www.openwall.com/lists/oss-security/2024/05/27/6", + "http://www.openwall.com/lists/oss-security/2024/04/18/4", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/P3I4KYS6EU6S7QZ47WFNTPVAHFIUQNEL/" + ], + "extended_information": { + "short_description": "An out-of-bound write vulnerability in Glibc can lead to denial of service when using a specific character set.", + "full_description": "[Glibc](https://www.gnu.org/software/libc/) is a library that provides core libraries with API functions.\n\n`ISO-2022-CN` is a 7-bit Chinese character encoding that supports simplified and traditional Chinese characters. `ISO-2022-CN-EXT` is an extension of `ISO-2022-CN` that supports other GB character sets.\n\nThe vulnerability was introduced in the GNU C Library versions 2.39 in the `iconv()` function.\nAttackers can use the out-of-bounds write vulnerability by overflowing the buffer passed to the `iconv()` function and potentially overwriting the neighboring variables or crashing the application.\n`SS2designation` and `SS3designation` do not perform the necessary boundary checks, allowing attackers to overflow of 1, 2, or 3 bytes with fixed values by converting the following strings to the `ISO-2022-CN-EXT` character set: '$+I', '$+J', '$+K', '$+L', '$+M', or '$*H'.\n\nThe researcher who found the vulnerability mentioned that it is not likely to be exploited in most libraries and programs except for PHP which was found to be applicable.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The researcher who found the vulnerability mentioned that it is not likely to be exploited in most libraries and programs except for PHP which was found to be applicable.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "This issue can lead to a Denial of Service." + }, + { + "name": "The issue has multiple mentions in general media", + "description": "The vulnerability was discussed at the OffensiveCon conference." + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-49460", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", + "cwe": [ + "NVD-CWE-noinfo" + ] + } + ], + "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the function UncompressedImageCodec::decode_uncompressed_image.", + "severity": "High", + "components": { + "deb://debian:bookworm:libheif1:1.15.1-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", + "full_path": "libheif1:1.15.1-1" + } + ] + ] + } + }, + "issue_id": "XRAY-540353", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2023-49460", + "https://github.com/strukturag/libheif/issues/1046" + ], + "extended_information": { + "short_description": "A NULL pointer dereference in libheif may lead to denial of service when parsing crafted images.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "A proof-of-concept was published in the report's GitHub Issue." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "To successfully exploit this vulnerability an attacker needs to find a way to propagate input into the vulnerable `UncompressedImageCodec::decode_uncompressed_image` function.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS score does not reflect the context dependent exploitation and impact of this vulnerability.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-49463", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", + "cwe": [ + "NVD-CWE-noinfo" + ] + } + ], + "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the function find_exif_tag at /libheif/exif.cc.", + "severity": "High", + "components": { + "deb://debian:bookworm:libheif1:1.15.1-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", + "full_path": "libheif1:1.15.1-1" + } + ] + ] + } + }, + "issue_id": "XRAY-540355", + "references": [ + "https://github.com/strukturag/libheif/issues/1042", + "https://github.com/strukturag/libheif", + "https://security-tracker.debian.org/tracker/CVE-2023-49463" + ], + "extended_information": { + "short_description": "An integer overflow in libheif leads to denial of service.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS score does not reflect the context dependent exploitation of this vulnerability.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "A proof-of-concept was published along with the vulnerability via (GitHub)[https://github.com/strukturag/libheif/issues/1042]." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "To successfully exploit this vulnerability an attacker needs to find a way to propagate input into the vulnerable functions `modify_exif_tag_if_it_exists(unsigned char*, unsigned int, unsigned short, unsigned short)` or `read_exif_orientation_tag(unsigned char const*, unsigned int)`.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Successful exploitation of this vulnerability leads to denial of service." + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-29659", + "cvss_v3_score": "6.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-369" + ], + "cwe_details": { + "CWE-369": { + "name": "Divide By Zero", + "description": "The product divides a value by zero." + } + } + } + ], + "summary": "A Segmentation fault caused by a floating point exception exists in libheif 1.15.1 using crafted heif images via the heif::Fraction::round() function in box.cc, which causes a denial of service.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libheif1:1.15.1-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", + "full_path": "libheif1:1.15.1-1" + } + ] + ] + } + }, + "issue_id": "XRAY-519184", + "references": [ + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/CKAE6NQBA3Q7GS6VTNDZRZZZVPPEFUEZ/", + "https://github.com/strukturag/libheif/issues/794", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LGKHDCS4HRZE3UGXYYDYPTIPNIBRLQ5L/", + "https://security-tracker.debian.org/tracker/CVE-2023-29659" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-25269" + } + ], + "summary": "libheif \u003c= 1.17.6 contains a memory leak in the function JpegEncoder::Encode. This flaw allows an attacker to cause a denial of service attack.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libheif1:1.15.1-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", + "full_path": "libheif1:1.15.1-1" + } + ] + ] + } + }, + "issue_id": "XRAY-593085", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-25269", + "https://github.com/strukturag/libheif/issues/1073" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-49464", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", + "cwe": [ + "NVD-CWE-noinfo" + ] + } + ], + "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the function UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci.", + "severity": "High", + "components": { + "deb://debian:bookworm:libheif1:1.15.1-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", + "full_path": "libheif1:1.15.1-1" + } + ] + ] + } + }, + "issue_id": "XRAY-540356", + "references": [ + "https://github.com/strukturag/libheif/issues/1044", + "https://security-tracker.debian.org/tracker/CVE-2023-49464" + ], + "extended_information": { + "short_description": "A use-after-free in libheif leads to denial of service and possibly remote code execution.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS score given to this CVE does not take into account the unlikely prerequisites for applicability of this vulnerability and the context required to exploit it.", + "is_positive": true + }, + { + "name": "The issue has an exploit published", + "description": "The fixing PR contains a denial of service PoC" + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "An attacker needs to find a remote input that propagates into the function `UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci`.", + "is_positive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "For this vulnerability to be applicable, `libheif1` needs to be compiled with the flag `-DWITH_UNCOMPRESSED_CODEC=ON`.\n\nWe found that this setting is enabled only in some package managers by default, but not all of them. In vanilla compilations, this flag is disabled by default.", + "is_positive": true + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Exploitation requires triggering a use-after-free beyond the scope of a single function. The use-after-free has not been proven to be able to cause code execution.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-49462", + "cvss_v3_score": "8.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", + "cwe": [ + "NVD-CWE-noinfo" + ] + } + ], + "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the component /libheif/exif.cc.", + "severity": "High", + "components": { + "deb://debian:bookworm:libheif1:1.15.1-1": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", + "full_path": "libheif1:1.15.1-1" + } + ] + ] + } + }, + "issue_id": "XRAY-540354", + "references": [ + "https://github.com/strukturag/libheif/issues/1043", + "https://security-tracker.debian.org/tracker/CVE-2023-49462" + ], + "extended_information": { + "short_description": "An integer overflow in libheif leads to denial of service.", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "A proof-of-concept was published along with the vulnerability via (GitHub)[https://github.com/strukturag/libheif/issues/1043]." + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS score does not reflect the context dependent exploitation of this vulnerability.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "To successfully exploit this vulnerability an attacker needs to find a way to propagate input into the vulnerable functions `modify_exif_tag_if_it_exists(unsigned char*, unsigned int, unsigned short, unsigned short)` or `read_exif_orientation_tag(unsigned char const*, unsigned int)`.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Successful exploitation of this vulnerability leads to denial of service." + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2018-6829", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:N/A:N", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", + "cwe": [ + "CWE-327" + ], + "cwe_details": { + "CWE-327": { + "name": "Use of a Broken or Risky Cryptographic Algorithm", + "description": "The product uses a broken or risky cryptographic algorithm or protocol." + } + } + } + ], + "summary": "cipher/elgamal.c in Libgcrypt through 1.8.2, when used to encrypt messages directly, improperly encodes plaintexts, which allows attackers to obtain sensitive information by reading ciphertext data (i.e., it does not have semantic security in face of a ciphertext-only attack). The Decisional Diffie-Hellman (DDH) assumption does not hold for Libgcrypt's ElGamal implementation.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libgcrypt20:1.10.1-3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libgcrypt20:1.10.1-3", + "full_path": "libgcrypt20:1.10.1-3" + } + ] + ] + } + }, + "issue_id": "XRAY-65914", + "references": [ + "https://github.com/weikengchen/attack-on-libgcrypt-elgamal/wiki", + "https://security-tracker.debian.org/tracker/CVE-2018-6829", + "https://lists.gnupg.org/pipermail/gcrypt-devel/2018-February/004394.html", + "https://www.oracle.com/security-alerts/cpujan2020.html", + "https://github.com/weikengchen/attack-on-libgcrypt-elgamal" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-2236", + "cwe": [ + "CWE-208" + ], + "cwe_details": { + "CWE-208": { + "name": "Observable Timing Discrepancy", + "description": "Two separate operations in a product require different amounts of time to complete, in a way that is observable to an actor and reveals security-relevant information about the state of the product, such as whether a particular operation was successful or not." + } + } + } + ], + "summary": "A timing-based side-channel flaw was found in libgcrypt's RSA implementation. This issue may allow a remote attacker to initiate a Bleichenbacher-style attack, which can lead to the decryption of RSA ciphertexts.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libgcrypt20:1.10.1-3": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libgcrypt20:1.10.1-3", + "full_path": "libgcrypt20:1.10.1-3" + } + ] + ] + } + }, + "issue_id": "XRAY-593361", + "references": [ + "https://bugzilla.redhat.com/show_bug.cgi?id=2268268", + "https://bugzilla.redhat.com/show_bug.cgi?id=2245218", + "https://security-tracker.debian.org/tracker/CVE-2024-2236", + "https://access.redhat.com/security/cve/CVE-2024-2236" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-0553", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", + "cwe": [ + "CWE-203" + ], + "cwe_details": { + "CWE-203": { + "name": "Observable Discrepancy", + "description": "The product behaves differently or sends different responses under different circumstances in a way that is observable to an unauthorized actor, which exposes security-relevant information about the state of the product, such as whether a particular operation was successful or not." + } + } + } + ], + "summary": "A vulnerability was found in GnuTLS. The response times to malformed ciphertexts in RSA-PSK ClientKeyExchange differ from the response times of ciphertexts with correct PKCS#1 v1.5 padding. This issue may allow a remote attacker to perform a timing side-channel attack in the RSA-PSK key exchange, potentially leading to the leakage of sensitive data. CVE-2024-0553 is designated as an incomplete resolution for CVE-2023-5981.", + "severity": "High", + "components": { + "deb://debian:bookworm:libgnutls30:3.7.9-2": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", + "full_path": "libgnutls30:3.7.9-2" + } + ] + ] + } + }, + "issue_id": "XRAY-588549", + "references": [ + "https://access.redhat.com/errata/RHSA-2024:2094", + "https://access.redhat.com/errata/RHSA-2024:0627", + "https://gitlab.com/gnutls/gnutls/-/issues/1522", + "https://access.redhat.com/errata/RHSA-2024:1383", + "https://access.redhat.com/errata/RHSA-2024:0796", + "http://www.openwall.com/lists/oss-security/2024/01/19/3", + "https://security.netapp.com/advisory/ntap-20240202-0011/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNXKVR5YNUEBNHAHM5GSYKBZX4W2HMN2/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/7ZEIOLORQ7N6WRPFXZSYDL2MC4LP7VFV/", + "https://lists.gnupg.org/pipermail/gnutls-help/2024-January/004841.html", + "https://access.redhat.com/errata/RHSA-2024:1108", + "https://lists.debian.org/debian-lts-announce/2024/02/msg00010.html", + "https://access.redhat.com/security/cve/CVE-2024-0553", + "https://access.redhat.com/errata/RHSA-2024:0533", + "https://access.redhat.com/errata/RHSA-2024:1082", + "https://bugzilla.redhat.com/show_bug.cgi?id=2258412", + "https://security-tracker.debian.org/tracker/CVE-2024-0553" + ], + "extended_information": { + "short_description": "A design problem in GnuTLS may lead to RSA key brute force when attackers can cause many decryption operations.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue can be exploited by attackers over the network", + "description": "This vulnerability does not rely on timing to exploit, but rather on the server informing the client that decryption failed, hence it can be exploited remotely, completely disregarding latency issues." + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The given CVSS score does not take the context required to exploit the vulnerability into account.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "This CVE is only exploitable when all of the following conditions are met:\n\n1. The server must use `RSA` for key exchange.\n2. The server encrypts/decrypts `RSA` with `PKCS#1 v1.5` padding.\n3. The server informs the client when decryption fails.\n4. An attacker is on the same subnet, hijacks a session between the client and the server and manipulates the client data.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "A successful attack would compromise the server's private RSA key, allowing the attacker to decrypt any sniffed TLS traffic sent to or from the server from any host." + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Although Bleichenbacher's Attack is well documented today, a high technical understanding of cryptography is required to exploit it.", + "is_positive": true + } + ], + "remediation": "##### Development mitigations\n\n- When choosing a key exchange for your server, avoid using `RSA` and instead opt for the `Diffie-Hellman` key exchange, which provides forward secrecy.\nThis can be done by generating an ECDH key using OpenSSL:\n`openssl ecparam -name prime256v1 -genkey -noout -out mykey-prime256v1.pem`\nAnd giving the filepath of the keyfile to the `gnutls_certificate_set_x509_key_file` function - \n```c\ngnutls_certificate_set_x509_key_file(res, certfile, \"mykey-prime256v1.pem\", GNUTLS_X509_FMT_PEM);\n```\n\n- When using `RSA` for key exchange, use the `OAEP` padding scheme instead of `PKCS#1 v1.5`.\n\n- When using `RSA` and `PKCS#1` for key exchange, avoid informing the client of decryption failure." + } + }, + { + "cves": [ + { + "cve": "CVE-2024-28834", + "cwe": [ + "CWE-200" + ], + "cwe_details": { + "CWE-200": { + "name": "Exposure of Sensitive Information to an Unauthorized Actor", + "description": "The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information." + } + } + } + ], + "summary": "A flaw was found in GnuTLS. The Minerva attack is a cryptographic vulnerability that exploits deterministic behavior in systems like GnuTLS, leading to side-channel leaks. In specific scenarios, such as when using the GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE flag, it can result in a noticeable step in nonce size from 513 to 512 bits, exposing a potential timing side-channel.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libgnutls30:3.7.9-2": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", + "full_path": "libgnutls30:3.7.9-2" + } + ] + ] + } + }, + "issue_id": "XRAY-594374", + "references": [ + "https://access.redhat.com/errata/RHSA-2024:1784", + "https://access.redhat.com/errata/RHSA-2024:2044", + "https://access.redhat.com/security/cve/CVE-2024-28834", + "http://www.openwall.com/lists/oss-security/2024/03/22/1", + "https://access.redhat.com/errata/RHSA-2024:1997", + "https://lists.gnupg.org/pipermail/gnutls-help/2024-March/004845.html", + "https://access.redhat.com/errata/RHSA-2024:2570", + "https://security-tracker.debian.org/tracker/CVE-2024-28834", + "http://www.openwall.com/lists/oss-security/2024/03/22/2", + "https://access.redhat.com/errata/RHSA-2024:1879", + "https://security.netapp.com/advisory/ntap-20240524-0004/", + "https://bugzilla.redhat.com/show_bug.cgi?id=2269228", + "https://access.redhat.com/errata/RHSA-2024:2889", + "https://minerva.crocs.fi.muni.cz/", + "https://people.redhat.com/~hkario/marvin/" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-28835", + "cwe": [ + "CWE-248" + ], + "cwe_details": { + "CWE-248": { + "name": "Uncaught Exception", + "description": "An exception is thrown from a function, but it is not caught." + } + } + } + ], + "summary": "A flaw has been discovered in GnuTLS where an application crash can be induced when attempting to verify a specially crafted .pem bundle using the \"certtool --verify-chain\" command.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libgnutls30:3.7.9-2": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", + "full_path": "libgnutls30:3.7.9-2" + } + ] + ] + } + }, + "issue_id": "XRAY-594364", + "references": [ + "http://www.openwall.com/lists/oss-security/2024/03/22/2", + "https://bugzilla.redhat.com/show_bug.cgi?id=2269084", + "https://access.redhat.com/errata/RHSA-2024:2570", + "https://lists.gnupg.org/pipermail/gnutls-help/2024-March/004845.html", + "https://security-tracker.debian.org/tracker/CVE-2024-28835", + "https://access.redhat.com/errata/RHSA-2024:2889", + "https://access.redhat.com/security/cve/CVE-2024-28835", + "https://access.redhat.com/errata/RHSA-2024:1879", + "http://www.openwall.com/lists/oss-security/2024/03/22/1" + ] + }, + { + "cves": [ + { + "cve": "CVE-2011-3389", + "cvss_v2_score": "4.3", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:P/I:N/A:N", + "cwe": [ + "CWE-326" + ], + "cwe_details": { + "CWE-326": { + "name": "Inadequate Encryption Strength", + "description": "The product stores or transmits sensitive data using an encryption scheme that is theoretically sound, but is not strong enough for the level of protection required." + } + } + } + ], + "summary": "The SSL protocol, as used in certain configurations in Microsoft Windows and Microsoft Internet Explorer, Mozilla Firefox, Google Chrome, Opera, and other products, encrypts data by using CBC mode with chained initialization vectors, which allows man-in-the-middle attackers to obtain plaintext HTTP headers via a blockwise chosen-boundary attack (BCBA) on an HTTPS session, in conjunction with JavaScript code that uses (1) the HTML5 WebSocket API, (2) the Java URLConnection API, or (3) the Silverlight WebClient API, aka a \"BEAST\" attack.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libgnutls30:3.7.9-2": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", + "full_path": "libgnutls30:3.7.9-2" + } + ] + ] + } + }, + "issue_id": "XRAY-42166", + "references": [ + "http://www.opera.com/docs/changelogs/mac/1160/", + "http://www.securityfocus.com/bid/49388", + "http://secunia.com/advisories/55322", + "http://support.apple.com/kb/HT5501", + "http://my.opera.com/securitygroup/blog/2011/09/28/the-beast-ssl-tls-issue", + "http://www.redhat.com/support/errata/RHSA-2012-0006.html", + "http://secunia.com/advisories/48256", + "http://www.opera.com/docs/changelogs/unix/1160/", + "http://marc.info/?l=bugtraq\u0026m=133365109612558\u0026w=2", + "http://technet.microsoft.com/security/advisory/2588513", + "http://marc.info/?l=bugtraq\u0026m=133728004526190\u0026w=2", + "http://secunia.com/advisories/45791", + "https://cert-portal.siemens.com/productcert/pdf/ssa-556833.pdf", + "http://www.securitytracker.com/id?1026704", + "http://support.apple.com/kb/HT5130", + "https://hermes.opensuse.org/messages/13155432", + "http://vnhacker.blogspot.com/2011/09/beast.html", + "http://downloads.asterisk.org/pub/security/AST-2016-001.html", + "https://bugzilla.redhat.com/show_bug.cgi?id=737506", + "http://lists.apple.com/archives/security-announce/2012/May/msg00001.html", + "http://www.opera.com/docs/changelogs/unix/1151/", + "http://secunia.com/advisories/48948", + "http://support.apple.com/kb/HT5001", + "https://blogs.oracle.com/sunsecurity/entry/multiple_vulnerabilities_in_fetchmail", + "http://support.apple.com/kb/HT4999", + "http://www.us-cert.gov/cas/techalerts/TA12-010A.html", + "https://security-tracker.debian.org/tracker/CVE-2011-3389", + "http://lists.opensuse.org/opensuse-security-announce/2012-05/msg00009.html", + "http://rhn.redhat.com/errata/RHSA-2013-1455.html", + "https://docs.microsoft.com/en-us/security-updates/securitybulletins/2012/ms12-006", + "http://secunia.com/advisories/55350", + "http://googlechromereleases.blogspot.com/2011/10/chrome-stable-release.html", + "http://lists.opensuse.org/opensuse-security-announce/2020-01/msg00040.html", + "http://www.opera.com/docs/changelogs/windows/1151/", + "http://support.apple.com/kb/HT5281", + "http://support.apple.com/kb/HT6150", + "http://www.debian.org/security/2012/dsa-2398", + "http://www.opera.com/support/kb/view/1004/", + "http://www.educatedguesswork.org/2011/09/security_impact_of_the_rizzodu.html", + "http://marc.info/?l=bugtraq\u0026m=132750579901589\u0026w=2", + "http://isc.sans.edu/diary/SSL+TLS+part+3+/11635", + "http://lists.apple.com/archives/security-announce/2012/Jul/msg00001.html", + "https://h20564.www2.hp.com/portal/site/hpsc/public/kb/docDisplay?docId=emr_na-c03839862", + "http://www.ibm.com/developerworks/java/jdk/alerts/", + "https://bugzilla.novell.com/show_bug.cgi?id=719047", + "http://lists.opensuse.org/opensuse-security-announce/2012-01/msg00051.html", + "http://blogs.technet.com/b/srd/archive/2011/09/26/is-ssl-broken-more-about-security-advisory-2588513.aspx", + "http://curl.haxx.se/docs/adv_20120124B.html", + "http://secunia.com/advisories/48692", + "http://eprint.iacr.org/2006/136", + "http://secunia.com/advisories/55351", + "http://marc.info/?l=bugtraq\u0026m=134254866602253\u0026w=2", + "https://oval.cisecurity.org/repository/search/definition/oval%3Aorg.mitre.oval%3Adef%3A14752", + "http://www.oracle.com/technetwork/topics/security/javacpuoct2011-443431.html", + "http://www.securitytracker.com/id?1025997", + "http://lists.apple.com/archives/security-announce/2013/Oct/msg00004.html", + "http://www.securityfocus.com/bid/49778", + "http://www.insecure.cl/Beast-SSL.rar", + "http://www.mandriva.com/security/advisories?name=MDVSA-2012:058", + "http://www.redhat.com/support/errata/RHSA-2011-1384.html", + "http://rhn.redhat.com/errata/RHSA-2012-0508.html", + "http://secunia.com/advisories/47998", + "http://ekoparty.org/2011/juliano-rizzo.php", + "http://lists.apple.com/archives/security-announce/2012/Sep/msg00004.html", + "http://www.apcmedia.com/salestools/SJHN-7RKGNM/SJHN-7RKGNM_R4_EN.pdf", + "http://www.ubuntu.com/usn/USN-1263-1", + "http://www.oracle.com/technetwork/topics/security/cpujul2015-2367936.html", + "http://security.gentoo.org/glsa/glsa-201406-32.xml", + "http://eprint.iacr.org/2004/111", + "https://ics-cert.us-cert.gov/advisories/ICSMA-18-058-02", + "http://lists.apple.com/archives/security-announce/2012/Feb/msg00000.html", + "http://www.securitytracker.com/id?1026103", + "http://www.opera.com/docs/changelogs/mac/1151/", + "http://secunia.com/advisories/49198", + "http://marc.info/?l=bugtraq\u0026m=132872385320240\u0026w=2", + "http://blog.mozilla.com/security/2011/09/27/attack-against-tls-protected-communications/", + "http://secunia.com/advisories/48915", + "http://lists.apple.com/archives/Security-announce/2011//Oct/msg00001.html", + "http://www.opera.com/docs/changelogs/windows/1160/", + "http://blogs.technet.com/b/msrc/archive/2011/09/26/microsoft-releases-security-advisory-2588513.aspx", + "http://www.imperialviolet.org/2011/09/23/chromeandbeast.html", + "http://lists.opensuse.org/opensuse-security-announce/2012-01/msg00049.html", + "http://www.kb.cert.org/vuls/id/864643", + "http://security.gentoo.org/glsa/glsa-201203-02.xml", + "http://www.oracle.com/technetwork/topics/security/cpujan2015-1972971.html", + "http://osvdb.org/74829", + "http://lists.apple.com/archives/Security-announce/2011//Oct/msg00002.html", + "http://www.securitytracker.com/id/1029190", + "http://marc.info/?l=bugtraq\u0026m=134254957702612\u0026w=2", + "https://hermes.opensuse.org/messages/13154861" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-5981", + "cvss_v3_score": "5.9", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N", + "cwe": [ + "CWE-203" + ], + "cwe_details": { + "CWE-203": { + "name": "Observable Discrepancy", + "description": "The product behaves differently or sends different responses under different circumstances in a way that is observable to an unauthorized actor, which exposes security-relevant information about the state of the product, such as whether a particular operation was successful or not." + } + } + } + ], + "summary": "A vulnerability was found that the response times to malformed ciphertexts in RSA-PSK ClientKeyExchange differ from response times of ciphertexts with correct PKCS#1 v1.5 padding.", + "severity": "Medium", + "components": { + "deb://debian:bookworm:libgnutls30:3.7.9-2": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", + "full_path": "libgnutls30:3.7.9-2" + } + ] + ] + } + }, + "issue_id": "XRAY-537103", + "references": [ + "https://gnutls.org/security-new.html#GNUTLS-SA-2023-10-23", + "https://access.redhat.com/errata/RHSA-2024:0451", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNXKVR5YNUEBNHAHM5GSYKBZX4W2HMN2/", + "http://www.openwall.com/lists/oss-security/2024/01/19/3", + "https://access.redhat.com/errata/RHSA-2024:0533", + "https://bugzilla.redhat.com/show_bug.cgi?id=2248445", + "https://access.redhat.com/errata/RHSA-2024:0319", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/7ZEIOLORQ7N6WRPFXZSYDL2MC4LP7VFV/", + "https://access.redhat.com/errata/RHSA-2024:1383", + "https://access.redhat.com/errata/RHSA-2024:0399", + "https://security-tracker.debian.org/tracker/CVE-2023-5981", + "https://access.redhat.com/security/cve/CVE-2023-5981", + "https://access.redhat.com/errata/RHSA-2024:0155" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-0567", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-347" + ], + "cwe_details": { + "CWE-347": { + "name": "Improper Verification of Cryptographic Signature", + "description": "The product does not verify, or incorrectly verifies, the cryptographic signature for data." + } + } + } + ], + "summary": "A vulnerability was found in GnuTLS, where a cockpit (which uses gnuTLS) rejects a certificate chain with distributed trust. This issue occurs when validating a certificate chain with cockpit-certificate-ensure. This flaw allows an unauthenticated, remote client or attacker to initiate a denial of service attack.", + "severity": "High", + "components": { + "deb://debian:bookworm:libgnutls30:3.7.9-2": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", + "full_path": "libgnutls30:3.7.9-2" + } + ] + ] + } + }, + "issue_id": "XRAY-588550", + "references": [ + "https://access.redhat.com/errata/RHSA-2024:2094", + "https://access.redhat.com/security/cve/CVE-2024-0567", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/7ZEIOLORQ7N6WRPFXZSYDL2MC4LP7VFV/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNXKVR5YNUEBNHAHM5GSYKBZX4W2HMN2/", + "https://bugzilla.redhat.com/show_bug.cgi?id=2258544", + "http://www.openwall.com/lists/oss-security/2024/01/19/3", + "https://security.netapp.com/advisory/ntap-20240202-0011/", + "https://access.redhat.com/errata/RHSA-2024:1383", + "https://lists.gnupg.org/pipermail/gnutls-help/2024-January/004841.html", + "https://access.redhat.com/errata/RHSA-2024:1082", + "https://security-tracker.debian.org/tracker/CVE-2024-0567", + "https://gitlab.com/gnutls/gnutls/-/issues/1521", + "https://access.redhat.com/errata/RHSA-2024:0533" + ], + "extended_information": { + "short_description": "A design problem in GnuTLS may lead to denial of service when parsing a crafted certificate chain.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The given CVSS score does not take into account the prerequisites and context required to exploit the vulnerability.", + "is_positive": true + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The vulnerability is only exploitable if a GnuTLS client or server calls any of the following functions with externally-supplied input -\n\n- `gnutls_pcert_import_x509_list`\n\n- `gnutls_certificate_set_x509_key`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_mem`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_file`\n\n- `gnutls_privkey_import_url`\n\n- `gnutls_privkey_import_pkcs11_url`\n\n- `gnutls_read_key_file`\n\n- `gnutls_certificate_set_rawpk_key_file`\n\n- `gnutls_certificate_set_x509_key_file2`\n\n- `gnutls_certificate_set_x509_key_file`\n\n- `gnutls_pcert_list_import_x509_file`\n\n- `gnutls_certificate_set_x509_key_mem2`\n\n- `gnutls_certificate_set_x509_key_mem`\n\n- `gnutls_x509_crt_list_import`\n\n- `gnutls_pcert_list_import_x509_raw`\n\n- `gnutls_session_channel_binding`\n\n- `gnutls_x509_crt_list_import2`\n\n- `gnutls_x509_trust_list_add_trust_mem`\n\n- `gnutls_x509_trust_list_add_system_trust`\n\n- `gnutls_certificate_set_x509_system_trust`\n\n- `gnutls_certificate_set_x509_crl_mem`\n\n- `gnutls_certificate_set_x509_trust_mem`\n\n- `gnutls_x509_trust_list_add_trust_file`\n\n- `gnutls_certificate_set_x509_crl_file`\n\n- `gnutls_certificate_set_x509_trust_file`\n\n- `gnutls_x509_trust_list_add_trust_dir`\n\n- `gnutls_certificate_set_x509_trust_dir`\n\n- `gnutls_x509_trust_list_remove_trust_mem`\n\n- `gnutls_x509_trust_list_remove_trust_file`\n\n- `gnutls_x509_trust_list_verify_crt2`\n\n- `gnutls_x509_cert_verify_peers`\n\n- `gnutls_certificate_verify_peers`\n\n- `gnutls_certificate_verify_peers2`\n\n- `gnutls_certificate_verify_peers3`\n\n- `gnutls_pkcs7_verify`\n\n- `gnutls_ocsp_resp_verify`\n\n- `gnutls_x509_trust_list_verify_crt`", + "is_positive": true + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2021-4214", + "cvss_v3_score": "5.5", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", + "cwe": [ + "CWE-120" + ], + "cwe_details": { + "CWE-120": { + "name": "Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')", + "description": "The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow." + } + } + } + ], + "summary": "A heap overflow flaw was found in libpngs' pngimage.c program. This flaw allows an attacker with local network access to pass a specially crafted PNG file to the pngimage utility, causing an application to crash, leading to a denial of service.", + "severity": "Low", + "components": { + "deb://debian:bookworm:libpng16-16:1.6.39-2": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", + "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" + }, + { + "component_id": "deb://debian:bookworm:libpng16-16:1.6.39-2", + "full_path": "libpng16-16:1.6.39-2" + } + ] + ] + } + }, + "issue_id": "XRAY-196432", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2021-4214", + "https://security.netapp.com/advisory/ntap-20221020-0001/", + "https://github.com/glennrp/libpng/issues/302", + "https://access.redhat.com/security/cve/CVE-2021-4214", + "https://bugzilla.redhat.com/show_bug.cgi?id=2043393" + ] + }, + { + "cves": [ + { + "cve": "CVE-2011-4116", + "cvss_v2_score": "5.0", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:P/A:N", + "cvss_v3_score": "7.5", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", + "cwe": [ + "CWE-59" + ], + "cwe_details": { + "CWE-59": { + "name": "Improper Link Resolution Before File Access ('Link Following')", + "description": "The product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource." + } + } + } + ], + "summary": "_is_safe in the File::Temp module for Perl does not properly handle symlinks.", + "severity": "Low", + "components": { + "deb://debian:bookworm:perl-base:5.36.0-7": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:perl-base:5.36.0-7", + "full_path": "perl-base:5.36.0-7" + } + ] + ] + } + }, + "issue_id": "XRAY-36310", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2011-4116", + "https://seclists.org/oss-sec/2011/q4/238", + "https://github.com/Perl-Toolchain-Gang/File-Temp/issues/14", + "http://www.openwall.com/lists/oss-security/2011/11/04/2", + "https://rt.cpan.org/Public/Bug/Display.html?id=69106", + "http://www.openwall.com/lists/oss-security/2011/11/04/4" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-31486", + "cvss_v3_score": "8.1", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-295" + ], + "cwe_details": { + "CWE-295": { + "name": "Improper Certificate Validation", + "description": "The product does not validate, or incorrectly validates, a certificate." + } + } + } + ], + "summary": "HTTP::Tiny before 0.083, a Perl core module since 5.13.9 and available standalone on CPAN, has an insecure default TLS configuration where users must opt in to verify certificates.", + "severity": "Low", + "components": { + "deb://debian:bookworm:perl-base:5.36.0-7": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:perl-base:5.36.0-7", + "full_path": "perl-base:5.36.0-7" + } + ] + ] + } + }, + "issue_id": "XRAY-515822", + "references": [ + "https://github.com/chansen/p5-http-tiny/pull/153", + "https://security-tracker.debian.org/tracker/CVE-2023-31486", + "http://www.openwall.com/lists/oss-security/2023/05/07/2", + "http://www.openwall.com/lists/oss-security/2023/04/29/1", + "http://www.openwall.com/lists/oss-security/2023/05/03/5", + "http://www.openwall.com/lists/oss-security/2023/05/03/3", + "https://www.reddit.com/r/perl/comments/111tadi/psa_httptiny_disabled_ssl_verification_by_default/", + "https://www.openwall.com/lists/oss-security/2023/05/03/4", + "https://hackeriet.github.io/cpan-http-tiny-overview/", + "https://blog.hackeriet.no/perl-http-tiny-insecure-tls-default-affects-cpan-modules/", + "https://www.openwall.com/lists/oss-security/2023/04/18/14" + ], + "extended_information": { + "short_description": "Missing TLS check in HTTP::Tiny allows network attackers to perform man-in-the-middle attacks when performing SSL requests.", + "full_description": "[HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) is an HTTP client written in Perl and a standalone CPAN module. By default, HTTP::Tiny does not verify TLS certificates. To enable verification, the `verify_SSL=\u003e1` flag must be specified when initializing the `HTTP::Tiny` object.\n\nThis could allow potential local-network attacker to perform a man-in-the-middle (ssl strip) attack.\nThis issue affects all packages that incorrectly use the `HTTP::Tiny` package.\n\nVulnerable code snippet -\n```\nuse HTTP::Tiny;\n\nmy $http = HTTP::Tiny-\u003enew();\nmy $response = $http-\u003eget('https://example.com');\n```", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue is trivial to exploit and does not require a published writeup or PoC", + "description": "Exploitation only requires an attacker to perform a man-in-the-middle attack (which is extensively documented)." + }, + { + "name": "The issue has a detailed technical explanation published, that can aid in exploit development", + "description": "A technical write-up exists." + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "The vulnerability is exploitable by local network attackers" + }, + { + "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", + "description": "The impact depends on the action performed by the vulnerable code.\nThis could be anything from information disclosure (through the web requests) to remote code execution (in the event the request response is used to install a package or influence the application's flow).", + "is_positive": true + } + ], + "remediation": "##### Development mitigations\n\nEnable the `verify_SSL` flag when initializing HTTP::Tiny -\n\n```perl\n$http = HTTP::Tiny-\u003enew(verify_SSL=\u003e1);\n```" + } + }, + { + "cves": [ + { + "cve": "CVE-2023-47038", + "cvss_v3_score": "7.8", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-787" + ], + "cwe_details": { + "CWE-787": { + "name": "Out-of-bounds Write", + "description": "The product writes data past the end, or before the beginning, of the intended buffer.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "1" + } + ] + } + } + } + ], + "summary": "A vulnerability was found in perl 5.30.0 through 5.38.0. This issue occurs when a crafted regular expression is compiled by perl, which can allow an attacker controlled byte buffer overflow in a heap allocated buffer.", + "severity": "High", + "components": { + "deb://debian:bookworm:perl-base:5.36.0-7": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:perl-base:5.36.0-7", + "full_path": "perl-base:5.36.0-7" + } + ] + ] + } + }, + "issue_id": "XRAY-539839", + "references": [ + "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1056746", + "https://access.redhat.com/errata/RHSA-2024:3128", + "https://access.redhat.com/security/cve/CVE-2023-47038", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNEEWAACXQCEEAKSG7XX2D5YDRWLCIZJ/", + "https://security-tracker.debian.org/tracker/CVE-2023-47038", + "https://bugzilla.redhat.com/show_bug.cgi?id=2249523", + "https://perldoc.perl.org/perl5382delta#CVE-2023-47038-Write-past-buffer-end-via-illegal-user-defined-Unicode-property", + "https://access.redhat.com/errata/RHSA-2024:2228" + ], + "extended_information": { + "short_description": "(non-issue) A heap buffer overflow in Perl leads to no impact when parsing a crafted regular expression.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ + { + "name": "The issue has an exploit published", + "description": "A test case is given, and is included in the Debian advisory:\n`perl -e 'qr/\\p{utf8::_perl_surrogate}/'`" + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "If the attacker can execute arbitrary Perl code, exploiting the vulnerability would offer no additional security impact.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The CVSS impact does not reflect the prerequisites required to exploit the vulnerability.", + "is_positive": true + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker must be able to run Perl code which the victim executes.", + "is_positive": true + } + ] + } + }, + { + "cves": [ + { + "cve": "CVE-2023-31484", + "cvss_v3_score": "8.1", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-295" + ], + "cwe_details": { + "CWE-295": { + "name": "Improper Certificate Validation", + "description": "The product does not validate, or incorrectly validates, a certificate." + } + } + } + ], + "summary": "CPAN.pm before 2.35 does not verify TLS certificates when downloading distributions over HTTPS.", + "severity": "High", + "components": { + "deb://debian:bookworm:perl-base:5.36.0-7": { + "impact_paths": [ + [ + { + "component_id": "docker://docker.io/library/nginx:latest" + }, + { + "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", + "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" + }, + { + "component_id": "deb://debian:bookworm:perl-base:5.36.0-7", + "full_path": "perl-base:5.36.0-7" + } + ] + ] + } + }, + "issue_id": "XRAY-515823", + "references": [ + "http://www.openwall.com/lists/oss-security/2023/04/29/1", + "https://security.netapp.com/advisory/ntap-20240621-0007/", + "http://www.openwall.com/lists/oss-security/2023/05/03/5", + "http://www.openwall.com/lists/oss-security/2023/05/03/3", + "https://blog.hackeriet.no/perl-http-tiny-insecure-tls-default-affects-cpan-modules/", + "http://www.openwall.com/lists/oss-security/2023/05/07/2", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/BM6UW55CNFUTNGD5ZRKGUKKKFDJGMFHL/", + "https://metacpan.org/dist/CPAN/changes", + "https://security-tracker.debian.org/tracker/CVE-2023-31484", + "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LEGCEOKFJVBJ2QQ6S2H4NAEWTUERC7SB/", + "https://github.com/andk/cpanpm/pull/175", + "https://www.openwall.com/lists/oss-security/2023/04/18/14" + ], + "extended_information": { + "short_description": "Missing TLS check in CPAN.pm allows man-in-the-middle attacks when downloading packages and may lead to code execution.", + "full_description": "[CPAN.pm](https://metacpan.org/pod/CPAN) is a Perl module and command-line tool that provides an automated and standardized way to download, install, and manage Perl modules and their dependencies from the Comprehensive Perl Archive Network (CPAN).\n[HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) is an HTTP client in Perl and a standalone CPAN module. By default, it does not verify TLS certificates. To enable it, the `verify_SSL=\u003e1` flag should be specified when initializing the `HTTP::Tiny` object. The problem identified in `HTTP::Tiny` has been assigned the CVE identifier `CVE-2023-31486` and serves as the underlying cause for the problem in `CPAN.pm`.\n\n`CPAN.pm` downloads and executes code through the `install` command followed by the package name.\nAlthough `CPAN.pm` downloads from `https://cpan.org`, it does not enable TLS certificate verification while using `HTTP::Tiny`, which could potentially allow an attacker to perform a man-in-the-middle attack by injecting malicious data that could be executed by CPAN.pm.\n\nExample of a vulnerable code:\n```\nuse CPAN;\ninstall DateTime\n```\n\nExample of a vulnerable command-line:\n```\ncpan install DateTime\n```", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "The issue is trivial to exploit and does not require a published writeup or PoC", + "description": "Exploitation only requires an attacker to perform a man-in-the-middle attack (which is extensively documented) and provide the victim with a malicious package instead of the legitimate one." + }, + { + "name": "The issue has a detailed technical explanation published, that can aid in exploit development", + "description": "A technical write-up exists." + }, + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The attacker should be in the network to perform a man-in-the-middle attack, and then provide a malicious package when the victim installs a new CPAN.pm package.", + "is_positive": true + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "This issue may lead to code execution." + }, + { + "name": "The issue can be exploited by attackers over the network" + } + ] + } + } + ], + "component_id": "docker://docker.io/library/nginx:latest", + "package_type": "oci", + "status": "completed" + } + ] + }, + "jas_scans": { + "contextual_analysis": [ + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Applicability Scanner", + "rules": [ + { + "id": "applic_CVE-2011-3374", + "name": "CVE-2011-3374", + "shortDescription": { + "text": "Scanner for CVE-2011-3374" + }, + "fullDescription": { + "text": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", + "markdown": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2013-0337", + "name": "CVE-2013-0337", + "shortDescription": { + "text": "Scanner for CVE-2013-0337" + }, + "fullDescription": { + "text": "The scanner checks whether any of the Nginx log files (`error.log` and `access.log`) is a symbolic link. If both files are symbolic links that point to `\\dev\\*` path, the vulnerability is not relevant, thus not applicable. If one of the log files is not a symbolic link, the vulnerability is applicable.", + "markdown": "The scanner checks whether any of the Nginx log files (`error.log` and `access.log`) is a symbolic link. If both files are symbolic links that point to `\\dev\\*` path, the vulnerability is not relevant, thus not applicable. If one of the log files is not a symbolic link, the vulnerability is applicable." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2018-5709", + "name": "CVE-2018-5709", + "shortDescription": { + "text": "Scanner for CVE-2018-5709" + }, + "fullDescription": { + "text": "This CVE has no security impact, hence it is never applicable.\nOriginally, the vulnerability was mistakenly reported as an integer overflow, but it is actually an integer truncation.\nThe issue does not affect any other data allocated close to the 16-bit integer in question. Furthermore, a negative value of the 16-bit integer does not impact the flow of the program in any meaningful way.", + "markdown": "This CVE has no security impact, hence it is never applicable.\nOriginally, the vulnerability was mistakenly reported as an integer overflow, but it is actually an integer truncation.\nThe issue does not affect any other data allocated close to the 16-bit integer in question. Furthermore, a negative value of the 16-bit integer does not impact the flow of the program in any meaningful way." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-5171", + "name": "CVE-2024-5171", + "shortDescription": { + "text": "Scanner for CVE-2024-5171" + }, + "fullDescription": { + "text": "The scanner checks whether any of the vulnerable functions are called:\n\n* `aom_img_alloc()`\n\n* `aom_img_wrap()`\n\n* `aom_img_alloc_with_border()`", + "markdown": "The scanner checks whether any of the vulnerable functions are called:\n\n* `aom_img_alloc()`\n\n* `aom_img_wrap()`\n\n* `aom_img_alloc_with_border()`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-39616", + "name": "CVE-2023-39616", + "shortDescription": { + "text": "Scanner for CVE-2023-39616" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `aom_codec_encode` is called.\n\nIn order for the vulnerability to be fully applicable, the vulnerable code must also call the `aom_codec_enc_init` function with the 3rd argument struct (`config`) being set with `dropframe_thresh` == 1. This additional condition is currently not checked by the scanner.\n\nNote that the vulnerability is also exploitable through the CLI tool `aomenc` under rare conditions. However - exploitation of the CLI tool will cause it to simply crash, which has no security impact (crashing of a forked client process).", + "markdown": "The scanner checks whether the vulnerable function `aom_codec_encode` is called.\n\nIn order for the vulnerability to be fully applicable, the vulnerable code must also call the `aom_codec_enc_init` function with the 3rd argument struct (`config`) being set with `dropframe_thresh` == 1. This additional condition is currently not checked by the scanner.\n\nNote that the vulnerability is also exploitable through the CLI tool `aomenc` under rare conditions. However - exploitation of the CLI tool will cause it to simply crash, which has no security impact (crashing of a forked client process)." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2022-0563", + "name": "CVE-2022-0563", + "shortDescription": { + "text": "Scanner for CVE-2022-0563" + }, + "fullDescription": { + "text": "The scanner checks whether the `chfs` and `chfn` CLI utilities are compiled with the vulnerable `readline` library.", + "markdown": "The scanner checks whether the `chfs` and `chfn` CLI utilities are compiled with the vulnerable `readline` library." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-27103", + "name": "CVE-2023-27103", + "shortDescription": { + "text": "Scanner for CVE-2023-27103" + }, + "fullDescription": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`", + "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-49465", + "name": "CVE-2023-49465", + "shortDescription": { + "text": "Scanner for CVE-2023-49465" + }, + "fullDescription": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`", + "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-49467", + "name": "CVE-2023-49467", + "shortDescription": { + "text": "Scanner for CVE-2023-49467" + }, + "fullDescription": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`", + "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-49468", + "name": "CVE-2023-49468", + "shortDescription": { + "text": "Scanner for CVE-2023-49468" + }, + "fullDescription": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`", + "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-52425", + "name": "CVE-2023-52425", + "shortDescription": { + "text": "Scanner for CVE-2023-52425" + }, + "fullDescription": { + "text": "The scanner checks whether any of the next functions are called:\n\n* `XML_Parse()`\n* `XML_ParseBuffer()`\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: The vulnerable functions are used to parse an attacker-controlled file by chunks.", + "markdown": "The scanner checks whether any of the next functions are called:\n\n* `XML_Parse()`\n* `XML_ParseBuffer()`\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: The vulnerable functions are used to parse an attacker-controlled file by chunks." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-45490", + "name": "CVE-2024-45490", + "shortDescription": { + "text": "Scanner for CVE-2024-45490" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `XML_Parse()`\n- `XML_ParseBuffer()`\n\nAn additional condition, which the scanner currently does not check, is that the `len` parameter which is passed to those functions is user-controlled.", + "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `XML_Parse()`\n- `XML_ParseBuffer()`\n\nAn additional condition, which the scanner currently does not check, is that the `len` parameter which is passed to those functions is user-controlled." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-26965", + "name": "CVE-2023-26965", + "shortDescription": { + "text": "Scanner for CVE-2023-26965" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable `tiffcrop` binary is present in the image.\n\nNote that the scanner does not check whether `tiffcrop` is invoked with arbitrary image files.", + "markdown": "The scanner checks whether the vulnerable `tiffcrop` binary is present in the image.\n\nNote that the scanner does not check whether `tiffcrop` is invoked with arbitrary image files." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-2953", + "name": "CVE-2023-2953", + "shortDescription": { + "text": "Scanner for CVE-2023-2953" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following vulnerable functions are used:\n\n- `ldif_open_url`\n- `ldif_fetch_url`\n- `ldif_parse_line2`\n- `ldif_parse_line`\n- `ldap_parse_ldif_record_x`\n- `ldap_parse_ldif_record`\n- `ldif_read_record`\n- `slapi_str2entry`", + "markdown": "The scanner checks whether any of the following vulnerable functions are used:\n\n- `ldif_open_url`\n- `ldif_fetch_url`\n- `ldif_parse_line2`\n- `ldif_parse_line`\n- `ldap_parse_ldif_record_x`\n- `ldap_parse_ldif_record`\n- `ldif_read_record`\n- `slapi_str2entry`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-40745", + "name": "CVE-2023-40745", + "shortDescription": { + "text": "Scanner for CVE-2023-40745" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-41175", + "name": "CVE-2023-41175", + "shortDescription": { + "text": "Scanner for CVE-2023-41175" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-43887", + "name": "CVE-2023-43887", + "shortDescription": { + "text": "Scanner for CVE-2023-43887" + }, + "fullDescription": { + "text": "The scanner checks for the presence of a binary related to `libde265` on the scanned artifact, specifically, any file ending with `dec265`.", + "markdown": "The scanner checks for the presence of a binary related to `libde265` on the scanned artifact, specifically, any file ending with `dec265`." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-44487", + "name": "CVE-2023-44487", + "shortDescription": { + "text": "Scanner for CVE-2023-44487" + }, + "fullDescription": { + "text": "The scanner checks for each vendor listed here:\n\n* Tomcat: configuration enables HTTP/2 either through the XML file or Java's `addUpgradeProtocol()` method.\n* Jetty: HTTP/2 enabled through `HTTP2CServerConnectionFactory`/`HTTP2ServerConnectionFactory` class initialization. Note: it also checks whether `jenkins` enables http/2 through its configuration.\n* Nginx: check whether one of the HTTP configurations is enabling http/2.\nNote: the following parameters should be configured properly to make the vulnerability not applicable:\n`keepalive_requests` should be kept at the default setting of 1000 requests\n`http2_max_concurrent_streams` should be kept at the default setting of 128 streams\n`limit_conn and limit_req` should be set `with a reasonable setting balancing application performance and security`. \n* Netty: check whether the `http2` codec classes are used in a java class\n* NodeJS: check whether the `http2.createSecureServer()` is used\n* NGHttp2: check whether a web server is instantiated through one of the symbols `nghttp2_session_server_new` or `listen_and_serve`.\n* Go: check whether a server is instantiated through the `net/http` or `net/http2` packages", + "markdown": "The scanner checks for each vendor listed here:\n\n* Tomcat: configuration enables HTTP/2 either through the XML file or Java's `addUpgradeProtocol()` method.\n* Jetty: HTTP/2 enabled through `HTTP2CServerConnectionFactory`/`HTTP2ServerConnectionFactory` class initialization. Note: it also checks whether `jenkins` enables http/2 through its configuration.\n* Nginx: check whether one of the HTTP configurations is enabling http/2.\nNote: the following parameters should be configured properly to make the vulnerability not applicable:\n`keepalive_requests` should be kept at the default setting of 1000 requests\n`http2_max_concurrent_streams` should be kept at the default setting of 128 streams\n`limit_conn and limit_req` should be set `with a reasonable setting balancing application performance and security`. \n* Netty: check whether the `http2` codec classes are used in a java class\n* NodeJS: check whether the `http2.createSecureServer()` is used\n* NGHttp2: check whether a web server is instantiated through one of the symbols `nghttp2_session_server_new` or `listen_and_serve`.\n* Go: check whether a server is instantiated through the `net/http` or `net/http2` packages" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-45853", + "name": "CVE-2023-45853", + "shortDescription": { + "text": "Scanner for CVE-2023-45853" + }, + "fullDescription": { + "text": "The scanner checks if any of the following functions are called:\n\n- `zipOpenNewFileInZip`\n- `zipOpenNewFileInZip_64`\n- `zipOpenNewFileInZip2`\n- `zipOpenNewFileInZip2_64`\n- `zipOpenNewFileInZip3`\n- `zipOpenNewFileInZip3_64`\n- `zipOpenNewFileInZip4`\n- `zipOpenNewFileInZip4_64`", + "markdown": "The scanner checks if any of the following functions are called:\n\n- `zipOpenNewFileInZip`\n- `zipOpenNewFileInZip_64`\n- `zipOpenNewFileInZip2`\n- `zipOpenNewFileInZip2_64`\n- `zipOpenNewFileInZip3`\n- `zipOpenNewFileInZip3_64`\n- `zipOpenNewFileInZip4`\n- `zipOpenNewFileInZip4_64`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-47038", + "name": "CVE-2023-47038", + "shortDescription": { + "text": "Scanner for CVE-2023-47038" + }, + "fullDescription": { + "text": "This CVE has no security impact (hence it is never applicable) as one of its prerequisites is arbitrary execution of Perl code, making any security impact of exploiting the vulnerability negligible since arbitrary code execution has already occurred.", + "markdown": "This CVE has no security impact (hence it is never applicable) as one of its prerequisites is arbitrary execution of Perl code, making any security impact of exploiting the vulnerability negligible since arbitrary code execution has already occurred." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-49460", + "name": "CVE-2023-49460", + "shortDescription": { + "text": "Scanner for CVE-2023-49460" + }, + "fullDescription": { + "text": "The scanner checks if the `libheif` binary was compiled with the vulnerable setting `-DWITH_UNCOMPRESSED_CODEC=ON` and if the vulnerable function `UncompressedImageCodec::decode_uncompressed_image` is called.", + "markdown": "The scanner checks if the `libheif` binary was compiled with the vulnerable setting `-DWITH_UNCOMPRESSED_CODEC=ON` and if the vulnerable function `UncompressedImageCodec::decode_uncompressed_image` is called." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-49463", + "name": "CVE-2023-49463", + "shortDescription": { + "text": "Scanner for CVE-2023-49463" + }, + "fullDescription": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `read_exif_orientation_tag`\n\n* `modify_exif_orientation_tag_if_it_exists`", + "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n* `read_exif_orientation_tag`\n\n* `modify_exif_orientation_tag_if_it_exists`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-49462", + "name": "CVE-2023-49462", + "shortDescription": { + "text": "Scanner for CVE-2023-49462" + }, + "fullDescription": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `read_exif_orientation_tag`\n\n* `modify_exif_orientation_tag_if_it_exists`", + "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n* `read_exif_orientation_tag`\n\n* `modify_exif_orientation_tag_if_it_exists`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-50387", + "name": "CVE-2023-50387", + "shortDescription": { + "text": "Scanner for CVE-2023-50387" + }, + "fullDescription": { + "text": "The scanner checks whether DNSSEC validation is on. Currently, the supported packages are `bind`, `dnsmasq`, `systemd`, `unbound`.\nFor bind, the scanner checks whether `dnssec-validation` configuration option is set to `auto` or `yes` in the bind configuration file.\n\nFor dnsmasq, the scanner checks whether the `dnssec` configuration appears in the dnsmasq configuration file.\n\nFor systemd, the scanner checks whether the `DNSSEC` configuration is set to `true` or `allow-downgrade` in the systemd-resolved configuration file.\n\nFor unbound, the scanner checks whether a `trust-anchor-file` or `auto-trust-anchor-file` file is set in the `server` configuration in the Unbound configuration file.\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: the attacker must be able to query the DNSSEC resolver to validate their malicious domain.", + "markdown": "The scanner checks whether DNSSEC validation is on. Currently, the supported packages are `bind`, `dnsmasq`, `systemd`, `unbound`.\nFor bind, the scanner checks whether `dnssec-validation` configuration option is set to `auto` or `yes` in the bind configuration file.\n\nFor dnsmasq, the scanner checks whether the `dnssec` configuration appears in the dnsmasq configuration file.\n\nFor systemd, the scanner checks whether the `DNSSEC` configuration is set to `true` or `allow-downgrade` in the systemd-resolved configuration file.\n\nFor unbound, the scanner checks whether a `trust-anchor-file` or `auto-trust-anchor-file` file is set in the `server` configuration in the Unbound configuration file.\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: the attacker must be able to query the DNSSEC resolver to validate their malicious domain." + }, + "properties": { + "applicability": "undetermined", + "conclusion": "private" + } + }, + { + "id": "applic_CVE-2023-50868", + "name": "CVE-2023-50868", + "shortDescription": { + "text": "Scanner for CVE-2023-50868" + }, + "fullDescription": { + "text": "The scanner checks whether DNSSEC validation is on. Currently, the supported packages are `bind`, `dnsmasq`, `systemd`, `unbound`.\nFor bind, the scanner checks whether `dnssec-validation` configuration option is set to `auto` or `yes` in the bind configuration file.\n\nFor dnsmasq, the scanner checks whether the `dnssec` configuration appears in the dnsmasq configuration file.\n\nFor systemd, the scanner checks whether the `DNSSEC` configuration is set to `true` or `allow-downgrade` in the systemd-resolved configuration file.\n\nFor unbound, the scanner checks whether a `trust-anchor-file` or `auto-trust-anchor-file` file is set in the `server` configuration in the Unbound configuration file.\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: the attacker must be able to query the DNSSEC resolver to validate their malicious domain.", + "markdown": "The scanner checks whether DNSSEC validation is on. Currently, the supported packages are `bind`, `dnsmasq`, `systemd`, `unbound`.\nFor bind, the scanner checks whether `dnssec-validation` configuration option is set to `auto` or `yes` in the bind configuration file.\n\nFor dnsmasq, the scanner checks whether the `dnssec` configuration appears in the dnsmasq configuration file.\n\nFor systemd, the scanner checks whether the `DNSSEC` configuration is set to `true` or `allow-downgrade` in the systemd-resolved configuration file.\n\nFor unbound, the scanner checks whether a `trust-anchor-file` or `auto-trust-anchor-file` file is set in the `server` configuration in the Unbound configuration file.\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: the attacker must be able to query the DNSSEC resolver to validate their malicious domain." + }, + "properties": { + "applicability": "undetermined", + "conclusion": "private" + } + }, + { + "id": "applic_CVE-2023-52355", + "name": "CVE-2023-52355", + "shortDescription": { + "text": "Scanner for CVE-2023-52355" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following functions are called:\n\n- `TIFFRasterScanlineSize64()`\n- `TIFFRasterScanlineSize()`", + "markdown": "The scanner checks whether any of the following functions are called:\n\n- `TIFFRasterScanlineSize64()`\n- `TIFFRasterScanlineSize()`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-52356", + "name": "CVE-2023-52356", + "shortDescription": { + "text": "Scanner for CVE-2023-52356" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following functions are called:\n\n- `TIFFReadRGBATileExt()` \n- `TIFFReadRGBATile()`", + "markdown": "The scanner checks whether any of the following functions are called:\n\n- `TIFFReadRGBATileExt()` \n- `TIFFReadRGBATile()`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-5363", + "name": "CVE-2023-5363", + "shortDescription": { + "text": "Scanner for CVE-2023-5363" + }, + "fullDescription": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n- `EVP_EncryptInit_ex2`\n- `EVP_DecryptInit_ex2`\n- `EVP_CipherInit_ex2`", + "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n- `EVP_EncryptInit_ex2`\n- `EVP_DecryptInit_ex2`\n- `EVP_CipherInit_ex2`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-6246", + "name": "CVE-2023-6246", + "shortDescription": { + "text": "Scanner for CVE-2023-6246" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable functions `syslog` or `vsyslog` are called from a file with the `setuid` or `setgid` bit.\n\nTo exploit this vulnerability, the attacker needs to control either argv[0], which typically holds the name of the program being executed or the `ident` argument of syslog's `openlog()` function. The scanner currently does not verify this prerequisite but for local exploitation, it is a common scenraio, such as in `su` binary.", + "markdown": "The scanner checks whether the vulnerable functions `syslog` or `vsyslog` are called from a file with the `setuid` or `setgid` bit.\n\nTo exploit this vulnerability, the attacker needs to control either argv[0], which typically holds the name of the program being executed or the `ident` argument of syslog's `openlog()` function. The scanner currently does not verify this prerequisite but for local exploitation, it is a common scenraio, such as in `su` binary." + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-6879", + "name": "CVE-2023-6879", + "shortDescription": { + "text": "Scanner for CVE-2023-6879" + }, + "fullDescription": { + "text": "The scanner checks whether an encoding process is performed with the following requirements:\n\n* Using AV1 codec (`aom_codec_av1_cx()`).\n* Encoding (`aom_codec_encode()`)\n* Cleaning the memory at the end of the encoding process (`aom_codec_destroy()`).\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: `aom` is configured to use more than 1 thread. For example:\n```\naom_codec_enc_cfg_t cfg;\naom_codec_enc_config_default(iface, \u0026cfg, AOM_USAGE_GOOD_QUALITY));\ncfg.g_threads = 4;\n```", + "markdown": "The scanner checks whether an encoding process is performed with the following requirements:\n\n* Using AV1 codec (`aom_codec_av1_cx()`).\n* Encoding (`aom_codec_encode()`)\n* Cleaning the memory at the end of the encoding process (`aom_codec_destroy()`).\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: `aom` is configured to use more than 1 thread. For example:\n```\naom_codec_enc_cfg_t cfg;\naom_codec_enc_config_default(iface, \u0026cfg, AOM_USAGE_GOOD_QUALITY));\ncfg.g_threads = 4;\n```" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-0553", + "name": "CVE-2024-0553", + "shortDescription": { + "text": "Scanner for CVE-2024-0553" + }, + "fullDescription": { + "text": "The scanner checks if RSA decryption occurs by finding calls to any of the following functions:\n\n- `gnutls_privkey_decrypt_data`\n\n- `gnutls_privkey_decrypt_data2`\n\nAn additional condition (that the scanner does not currently check) is required for the CVE to be applicable: the RSA padding algorithm needs to be `PKCS#1`. `key-\u003epk_algorithm` needs to be equal to `GNUTLS_PK_RSA`.", + "markdown": "The scanner checks if RSA decryption occurs by finding calls to any of the following functions:\n\n- `gnutls_privkey_decrypt_data`\n\n- `gnutls_privkey_decrypt_data2`\n\nAn additional condition (that the scanner does not currently check) is required for the CVE to be applicable: the RSA padding algorithm needs to be `PKCS#1`. `key-\u003epk_algorithm` needs to be equal to `GNUTLS_PK_RSA`." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-0567", + "name": "CVE-2024-0567", + "shortDescription": { + "text": "Scanner for CVE-2024-0567" + }, + "fullDescription": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n- `gnutls_pcert_import_x509_list`\n\n- `gnutls_certificate_set_x509_key`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_mem`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_file`\n\n- `gnutls_privkey_import_url`\n\n- `gnutls_privkey_import_pkcs11_url`\n\n- `gnutls_read_key_file`\n\n- `gnutls_certificate_set_rawpk_key_file`\n\n- `gnutls_certificate_set_x509_key_file2`\n\n- `gnutls_certificate_set_x509_key_file`\n\n- `gnutls_pcert_list_import_x509_file`\n\n- `gnutls_certificate_set_x509_key_mem2`\n\n- `gnutls_certificate_set_x509_key_mem`\n\n- `gnutls_x509_crt_list_import`\n\n- `gnutls_pcert_list_import_x509_raw`\n\n- `gnutls_session_channel_binding`\n\n- `gnutls_x509_crt_list_import2`\n\n- `gnutls_x509_trust_list_add_trust_mem`\n\n- `gnutls_x509_trust_list_add_system_trust`\n\n- `gnutls_certificate_set_x509_system_trust`\n\n- `gnutls_certificate_set_x509_crl_mem`\n\n- `gnutls_certificate_set_x509_trust_mem`\n\n- `gnutls_x509_trust_list_add_trust_file`\n\n- `gnutls_certificate_set_x509_crl_file`\n\n- `gnutls_certificate_set_x509_trust_file`\n\n- `gnutls_x509_trust_list_add_trust_dir`\n\n- `gnutls_certificate_set_x509_trust_dir`\n\n- `gnutls_x509_trust_list_remove_trust_mem`\n\n- `gnutls_x509_trust_list_remove_trust_file`\n\n- `gnutls_x509_trust_list_verify_crt2`\n\n- `gnutls_x509_cert_verify_peers`\n\n- `gnutls_certificate_verify_peers`\n\n- `gnutls_certificate_verify_peers2`\n\n- `gnutls_certificate_verify_peers3`\n\n- `gnutls_pkcs7_verify`\n\n- `gnutls_ocsp_resp_verify`\n\n- `gnutls_x509_trust_list_verify_crt`", + "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n- `gnutls_pcert_import_x509_list`\n\n- `gnutls_certificate_set_x509_key`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_mem`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_file`\n\n- `gnutls_privkey_import_url`\n\n- `gnutls_privkey_import_pkcs11_url`\n\n- `gnutls_read_key_file`\n\n- `gnutls_certificate_set_rawpk_key_file`\n\n- `gnutls_certificate_set_x509_key_file2`\n\n- `gnutls_certificate_set_x509_key_file`\n\n- `gnutls_pcert_list_import_x509_file`\n\n- `gnutls_certificate_set_x509_key_mem2`\n\n- `gnutls_certificate_set_x509_key_mem`\n\n- `gnutls_x509_crt_list_import`\n\n- `gnutls_pcert_list_import_x509_raw`\n\n- `gnutls_session_channel_binding`\n\n- `gnutls_x509_crt_list_import2`\n\n- `gnutls_x509_trust_list_add_trust_mem`\n\n- `gnutls_x509_trust_list_add_system_trust`\n\n- `gnutls_certificate_set_x509_system_trust`\n\n- `gnutls_certificate_set_x509_crl_mem`\n\n- `gnutls_certificate_set_x509_trust_mem`\n\n- `gnutls_x509_trust_list_add_trust_file`\n\n- `gnutls_certificate_set_x509_crl_file`\n\n- `gnutls_certificate_set_x509_trust_file`\n\n- `gnutls_x509_trust_list_add_trust_dir`\n\n- `gnutls_certificate_set_x509_trust_dir`\n\n- `gnutls_x509_trust_list_remove_trust_mem`\n\n- `gnutls_x509_trust_list_remove_trust_file`\n\n- `gnutls_x509_trust_list_verify_crt2`\n\n- `gnutls_x509_cert_verify_peers`\n\n- `gnutls_certificate_verify_peers`\n\n- `gnutls_certificate_verify_peers2`\n\n- `gnutls_certificate_verify_peers3`\n\n- `gnutls_pkcs7_verify`\n\n- `gnutls_ocsp_resp_verify`\n\n- `gnutls_x509_trust_list_verify_crt`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-25062", + "name": "CVE-2024-25062", + "shortDescription": { + "text": "Scanner for CVE-2024-25062" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following functions are called:\n\n* `xmlValidatePopElement()`\n* `xmlTextReaderClose()`\n* `xmlFreeTextReader() `\n* `xmlTextReaderRead()`\n* `xmlSchemaValidateDoc()`", + "markdown": "The scanner checks whether any of the following functions are called:\n\n* `xmlValidatePopElement()`\n* `xmlTextReaderClose()`\n* `xmlFreeTextReader() `\n* `xmlTextReaderRead()`\n* `xmlSchemaValidateDoc()`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-28182", + "name": "CVE-2024-28182", + "shortDescription": { + "text": "Scanner for CVE-2024-28182" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative" + } + }, + { + "id": "applic_CVE-2024-2961", + "name": "CVE-2024-2961", + "shortDescription": { + "text": "Scanner for CVE-2024-2961" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-33600", + "name": "CVE-2024-33600", + "shortDescription": { + "text": "Scanner for CVE-2024-33600" + }, + "fullDescription": { + "text": "The scanner checks whether the `nscd` binary exists on the machine.", + "markdown": "The scanner checks whether the `nscd` binary exists on the machine." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-33599", + "name": "CVE-2024-33599", + "shortDescription": { + "text": "Scanner for CVE-2024-33599" + }, + "fullDescription": { + "text": "The scanner checks whether the `nscd` binary exists on the machine.", + "markdown": "The scanner checks whether the `nscd` binary exists on the machine." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-4741", + "name": "CVE-2024-4741", + "shortDescription": { + "text": "Scanner for CVE-2024-4741" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called.", + "markdown": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-31484", + "name": "CVE-2023-31484", + "shortDescription": { + "text": "Scanner for CVE-2023-31484" + }, + "fullDescription": { + "text": "The scanner checks whether a script (either bash or perl) installs a package through the `CPAN.pm` module.", + "markdown": "The scanner checks whether a script (either bash or perl) installs a package through the `CPAN.pm` module." + }, + "properties": { + "applicability": "undetermined", + "conclusion": "private" + } + }, + { + "id": "applic_CVE-2023-49464", + "name": "CVE-2023-49464", + "shortDescription": { + "text": "Scanner for CVE-2023-49464" + }, + "fullDescription": { + "text": "The scanner checks for two conditions:\n\n1. The `libheif.so` binary was compiled with the vulnerable setting `-DWITH_UNCOMPRESSED_CODEC=ON`. \n\n2. Any of the following vulnerable functions are called:\n\n* `HeifContext::Image::get_luma_bits_per_pixel`\n* `HeifContext::decode_full_grid_image`\n* `HeifFile::get_luma_bits_per_pixel_from_configuration`\n* `UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci`\n* `heif_image_handle_get_luma_bits_per_pixel`", + "markdown": "The scanner checks for two conditions:\n\n1. The `libheif.so` binary was compiled with the vulnerable setting `-DWITH_UNCOMPRESSED_CODEC=ON`. \n\n2. Any of the following vulnerable functions are called:\n\n* `HeifContext::Image::get_luma_bits_per_pixel`\n* `HeifContext::decode_full_grid_image`\n* `HeifFile::get_luma_bits_per_pixel_from_configuration`\n* `UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci`\n* `heif_image_handle_get_luma_bits_per_pixel`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-6119", + "name": "CVE-2024-6119", + "shortDescription": { + "text": "Scanner for CVE-2024-6119" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`", + "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2019-1010022", + "name": "CVE-2019-1010022", + "shortDescription": { + "text": "Scanner for uncovered CVE-2019-1010022" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2019-3815", + "name": "CVE-2019-3815", + "shortDescription": { + "text": "Scanner for uncovered CVE-2019-3815" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-6228", + "name": "CVE-2023-6228", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-6228" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-27102", + "name": "CVE-2023-27102", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-27102" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-26462", + "name": "CVE-2024-26462", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-26462" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-34459", + "name": "CVE-2024-34459", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-34459" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2010-4756", + "name": "CVE-2010-4756", + "shortDescription": { + "text": "Scanner for uncovered CVE-2010-4756" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2017-17740", + "name": "CVE-2017-17740", + "shortDescription": { + "text": "Scanner for uncovered CVE-2017-17740" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-31437", + "name": "CVE-2023-31437", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-31437" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-4039", + "name": "CVE-2023-4039", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-4039" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-25269", + "name": "CVE-2024-25269", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-25269" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-2379", + "name": "CVE-2024-2379", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-2379" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-26458", + "name": "CVE-2024-26458", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-26458" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-6237", + "name": "CVE-2023-6237", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-6237" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2017-9117", + "name": "CVE-2017-9117", + "shortDescription": { + "text": "Scanner for uncovered CVE-2017-9117" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2022-3219", + "name": "CVE-2022-3219", + "shortDescription": { + "text": "Scanner for uncovered CVE-2022-3219" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-1916", + "name": "CVE-2023-1916", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-1916" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-37371", + "name": "CVE-2024-37371", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-37371" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2013-4392", + "name": "CVE-2013-4392", + "shortDescription": { + "text": "Scanner for uncovered CVE-2013-4392" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-2908", + "name": "CVE-2023-2908", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-2908" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-6277", + "name": "CVE-2023-6277", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-6277" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2017-17973", + "name": "CVE-2017-17973", + "shortDescription": { + "text": "Scanner for uncovered CVE-2017-17973" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2022-27943", + "name": "CVE-2022-27943", + "shortDescription": { + "text": "Scanner for uncovered CVE-2022-27943" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-4603", + "name": "CVE-2024-4603", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-4603" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-45491", + "name": "CVE-2024-45491", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-45491" + }, + "fullDescription": { + "text": "The scanner checks whether the `xmlwf` CLI tool exists or if the vulnerable function `XML_ExternalEntityParserCreate()` is called.\n\nThis CVE is applicable only when the platform is 32bit. The scanner currently does not check for this condition.", + "markdown": "The scanner checks whether the `xmlwf` CLI tool exists or if the vulnerable function `XML_ExternalEntityParserCreate()` is called.\n\nThis CVE is applicable only when the platform is 32bit. The scanner currently does not check for this condition." + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-7006", + "name": "CVE-2024-7006", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-7006" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-7008", + "name": "CVE-2023-7008", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-7008" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2015-3276", + "name": "CVE-2015-3276", + "shortDescription": { + "text": "Scanner for uncovered CVE-2015-3276" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-45918", + "name": "CVE-2023-45918", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-45918" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2019-9192", + "name": "CVE-2019-9192", + "shortDescription": { + "text": "Scanner for uncovered CVE-2019-9192" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-28757", + "name": "CVE-2024-28757", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-28757" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-32570", + "name": "CVE-2023-32570", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-32570" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2009-4487", + "name": "CVE-2009-4487", + "shortDescription": { + "text": "Scanner for uncovered CVE-2009-4487" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2011-0283", + "name": "CVE-2011-0283", + "shortDescription": { + "text": "Scanner for uncovered CVE-2011-0283" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-4641", + "name": "CVE-2023-4641", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-4641" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2012-2131", + "name": "CVE-2012-2131", + "shortDescription": { + "text": "Scanner for uncovered CVE-2012-2131" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2011-4116", + "name": "CVE-2011-4116", + "shortDescription": { + "text": "Scanner for uncovered CVE-2011-4116" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2017-9937", + "name": "CVE-2017-9937", + "shortDescription": { + "text": "Scanner for uncovered CVE-2017-9937" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-3164", + "name": "CVE-2023-3164", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-3164" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-38949", + "name": "CVE-2024-38949", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-38949" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-45492", + "name": "CVE-2024-45492", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-45492" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2019-1010024", + "name": "CVE-2019-1010024", + "shortDescription": { + "text": "Scanner for uncovered CVE-2019-1010024" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-0727", + "name": "CVE-2024-0727", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-0727" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-37370", + "name": "CVE-2024-37370", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-37370" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-5678", + "name": "CVE-2023-5678", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-5678" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2016-2781", + "name": "CVE-2016-2781", + "shortDescription": { + "text": "Scanner for uncovered CVE-2016-2781" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-31439", + "name": "CVE-2023-31439", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-31439" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-51792", + "name": "CVE-2023-51792", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-51792" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2021-4214", + "name": "CVE-2021-4214", + "shortDescription": { + "text": "Scanner for uncovered CVE-2021-4214" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-22365", + "name": "CVE-2024-22365", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-22365" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-31438", + "name": "CVE-2023-31438", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-31438" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2018-10126", + "name": "CVE-2018-10126", + "shortDescription": { + "text": "Scanner for uncovered CVE-2018-10126" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-33602", + "name": "CVE-2024-33602", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-33602" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2022-1210", + "name": "CVE-2022-1210", + "shortDescription": { + "text": "Scanner for uncovered CVE-2022-1210" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-3618", + "name": "CVE-2023-3618", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-3618" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-26966", + "name": "CVE-2023-26966", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-26966" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-6780", + "name": "CVE-2023-6780", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-6780" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2015-9019", + "name": "CVE-2015-9019", + "shortDescription": { + "text": "Scanner for uncovered CVE-2015-9019" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2010-4665", + "name": "CVE-2010-4665", + "shortDescription": { + "text": "Scanner for uncovered CVE-2010-4665" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-39615", + "name": "CVE-2023-39615", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-39615" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2017-16232", + "name": "CVE-2017-16232", + "shortDescription": { + "text": "Scanner for uncovered CVE-2017-16232" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2019-1010025", + "name": "CVE-2019-1010025", + "shortDescription": { + "text": "Scanner for uncovered CVE-2019-1010025" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-26461", + "name": "CVE-2024-26461", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-26461" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-6129", + "name": "CVE-2023-6129", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-6129" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-1580", + "name": "CVE-2024-1580", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-1580" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-29659", + "name": "CVE-2023-29659", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-29659" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-31486", + "name": "CVE-2023-31486", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-31486" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-29383", + "name": "CVE-2023-29383", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-29383" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2020-15719", + "name": "CVE-2020-15719", + "shortDescription": { + "text": "Scanner for uncovered CVE-2020-15719" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2017-5563", + "name": "CVE-2017-5563", + "shortDescription": { + "text": "Scanner for uncovered CVE-2017-5563" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-39804", + "name": "CVE-2023-39804", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-39804" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-2236", + "name": "CVE-2024-2236", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-2236" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2022-3636", + "name": "CVE-2022-3636", + "shortDescription": { + "text": "Scanner for uncovered CVE-2022-3636" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-46219", + "name": "CVE-2023-46219", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-46219" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2022-48303", + "name": "CVE-2022-48303", + "shortDescription": { + "text": "Scanner for uncovered CVE-2022-48303" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-5981", + "name": "CVE-2023-5981", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-5981" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-2398", + "name": "CVE-2024-2398", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-2398" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2011-3389", + "name": "CVE-2011-3389", + "shortDescription": { + "text": "Scanner for uncovered CVE-2011-3389" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-33601", + "name": "CVE-2024-33601", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-33601" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2019-1010023", + "name": "CVE-2019-1010023", + "shortDescription": { + "text": "Scanner for uncovered CVE-2019-1010023" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2007-5686", + "name": "CVE-2007-5686", + "shortDescription": { + "text": "Scanner for uncovered CVE-2007-5686" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-2511", + "name": "CVE-2024-2511", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-2511" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-28834", + "name": "CVE-2024-28834", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-28834" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-47471", + "name": "CVE-2023-47471", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-47471" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-45322", + "name": "CVE-2023-45322", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-45322" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-7347", + "name": "CVE-2024-7347", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-7347" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2017-14159", + "name": "CVE-2017-14159", + "shortDescription": { + "text": "Scanner for uncovered CVE-2017-14159" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-3576", + "name": "CVE-2023-3576", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-3576" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-25433", + "name": "CVE-2023-25433", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-25433" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-28085", + "name": "CVE-2024-28085", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-28085" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2018-20796", + "name": "CVE-2018-20796", + "shortDescription": { + "text": "Scanner for uncovered CVE-2018-20796" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-50495", + "name": "CVE-2023-50495", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-50495" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-38950", + "name": "CVE-2024-38950", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-38950" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-46218", + "name": "CVE-2023-46218", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-46218" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-5535", + "name": "CVE-2024-5535", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-5535" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-6779", + "name": "CVE-2023-6779", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-6779" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-28835", + "name": "CVE-2024-28835", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-28835" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2023-52426", + "name": "CVE-2023-52426", + "shortDescription": { + "text": "Scanner for uncovered CVE-2023-52426" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-7264", + "name": "CVE-2024-7264", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-7264" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2017-18018", + "name": "CVE-2017-18018", + "shortDescription": { + "text": "Scanner for uncovered CVE-2017-18018" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2018-6829", + "name": "CVE-2018-6829", + "shortDescription": { + "text": "Scanner for uncovered CVE-2018-6829" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2005-2541", + "name": "CVE-2005-2541", + "shortDescription": { + "text": "Scanner for uncovered CVE-2005-2541" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2024-2004", + "name": "CVE-2024-2004", + "shortDescription": { + "text": "Scanner for uncovered CVE-2024-2004" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + }, + { + "id": "applic_CVE-2019-19882", + "name": "CVE-2019-19882", + "shortDescription": { + "text": "Scanner for uncovered CVE-2019-19882" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "not_covered" + } + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1725978580-3584350251/Applicability_1725978580/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1725978503-2625964325/image.tar" + } + } + ], + "results": [ + { + "ruleId": "applic_CVE-2011-3374", + "kind": "pass", + "message": { + "text": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." + } + }, + { + "ruleId": "applic_CVE-2013-0337", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the Nginx log files (`error.log` and `access.log`) is a symbolic link. If both files are symbolic links that point to `\\dev\\*` path, the vulnerability is not relevant, thus not applicable. If one of the log files is not a symbolic link, the vulnerability is applicable." + } + }, + { + "ruleId": "applic_CVE-2018-5709", + "kind": "pass", + "message": { + "text": "This CVE has no security impact, hence it is never applicable.\nOriginally, the vulnerability was mistakenly reported as an integer overflow, but it is actually an integer truncation.\nThe issue does not affect any other data allocated close to the 16-bit integer in question. Furthermore, a negative value of the 16-bit integer does not impact the flow of the program in any meaningful way." + } + }, + { + "ruleId": "applic_CVE-2024-5171", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the vulnerable functions are called:\n\n* `aom_img_alloc()`\n\n* `aom_img_wrap()`\n\n* `aom_img_alloc_with_border()`" + } + }, + { + "ruleId": "applic_CVE-2023-39616", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `aom_codec_encode` is called.\n\nIn order for the vulnerability to be fully applicable, the vulnerable code must also call the `aom_codec_enc_init` function with the 3rd argument struct (`config`) being set with `dropframe_thresh` == 1. This additional condition is currently not checked by the scanner.\n\nNote that the vulnerability is also exploitable through the CLI tool `aomenc` under rare conditions. However - exploitation of the CLI tool will cause it to simply crash, which has no security impact (crashing of a forked client process)." + } + }, + { + "ruleId": "applic_CVE-2022-0563", + "kind": "pass", + "message": { + "text": "The scanner checks whether the `chfs` and `chfn` CLI utilities are compiled with the vulnerable `readline` library." + } + }, + { + "ruleId": "applic_CVE-2023-27103", + "kind": "pass", + "message": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" + } + }, + { + "ruleId": "applic_CVE-2023-49465", + "kind": "pass", + "message": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" + } + }, + { + "ruleId": "applic_CVE-2023-49467", + "kind": "pass", + "message": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" + } + }, + { + "ruleId": "applic_CVE-2023-49468", + "kind": "pass", + "message": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" + } + }, + { + "ruleId": "applic_CVE-2023-52425", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the next functions are called:\n\n* `XML_Parse()`\n* `XML_ParseBuffer()`\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: The vulnerable functions are used to parse an attacker-controlled file by chunks." + } + }, + { + "ruleId": "applic_CVE-2024-45490", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `XML_Parse()`\n- `XML_ParseBuffer()`\n\nAn additional condition, which the scanner currently does not check, is that the `len` parameter which is passed to those functions is user-controlled." + } + }, + { + "ruleId": "applic_CVE-2023-26965", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable `tiffcrop` binary is present in the image.\n\nNote that the scanner does not check whether `tiffcrop` is invoked with arbitrary image files." + } + }, + { + "ruleId": "applic_CVE-2023-2953", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the following vulnerable functions are used:\n\n- `ldif_open_url`\n- `ldif_fetch_url`\n- `ldif_parse_line2`\n- `ldif_parse_line`\n- `ldap_parse_ldif_record_x`\n- `ldap_parse_ldif_record`\n- `ldif_read_record`\n- `slapi_str2entry`" + } + }, + { + "ruleId": "applic_CVE-2023-40745", + "kind": "pass", + "message": { + "text": "" + } + }, + { + "ruleId": "applic_CVE-2023-41175", + "kind": "pass", + "message": { + "text": "" + } + }, + { + "ruleId": "applic_CVE-2023-43887", + "kind": "pass", + "message": { + "text": "The scanner checks for the presence of a binary related to `libde265` on the scanned artifact, specifically, any file ending with `dec265`." + } + }, + { + "ruleId": "applic_CVE-2023-44487", + "kind": "pass", + "message": { + "text": "The scanner checks for each vendor listed here:\n\n* Tomcat: configuration enables HTTP/2 either through the XML file or Java's `addUpgradeProtocol()` method.\n* Jetty: HTTP/2 enabled through `HTTP2CServerConnectionFactory`/`HTTP2ServerConnectionFactory` class initialization. Note: it also checks whether `jenkins` enables http/2 through its configuration.\n* Nginx: check whether one of the HTTP configurations is enabling http/2.\nNote: the following parameters should be configured properly to make the vulnerability not applicable:\n`keepalive_requests` should be kept at the default setting of 1000 requests\n`http2_max_concurrent_streams` should be kept at the default setting of 128 streams\n`limit_conn and limit_req` should be set `with a reasonable setting balancing application performance and security`. \n* Netty: check whether the `http2` codec classes are used in a java class\n* NodeJS: check whether the `http2.createSecureServer()` is used\n* NGHttp2: check whether a web server is instantiated through one of the symbols `nghttp2_session_server_new` or `listen_and_serve`.\n* Go: check whether a server is instantiated through the `net/http` or `net/http2` packages" + } + }, + { + "ruleId": "applic_CVE-2023-45853", + "kind": "pass", + "message": { + "text": "The scanner checks if any of the following functions are called:\n\n- `zipOpenNewFileInZip`\n- `zipOpenNewFileInZip_64`\n- `zipOpenNewFileInZip2`\n- `zipOpenNewFileInZip2_64`\n- `zipOpenNewFileInZip3`\n- `zipOpenNewFileInZip3_64`\n- `zipOpenNewFileInZip4`\n- `zipOpenNewFileInZip4_64`" + } + }, + { + "ruleId": "applic_CVE-2023-47038", + "kind": "pass", + "message": { + "text": "This CVE has no security impact (hence it is never applicable) as one of its prerequisites is arbitrary execution of Perl code, making any security impact of exploiting the vulnerability negligible since arbitrary code execution has already occurred." + } + }, + { + "ruleId": "applic_CVE-2023-49460", + "kind": "pass", + "message": { + "text": "The scanner checks if the `libheif` binary was compiled with the vulnerable setting `-DWITH_UNCOMPRESSED_CODEC=ON` and if the vulnerable function `UncompressedImageCodec::decode_uncompressed_image` is called." + } + }, + { + "ruleId": "applic_CVE-2023-49463", + "kind": "pass", + "message": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `read_exif_orientation_tag`\n\n* `modify_exif_orientation_tag_if_it_exists`" + } + }, + { + "ruleId": "applic_CVE-2023-49462", + "kind": "pass", + "message": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `read_exif_orientation_tag`\n\n* `modify_exif_orientation_tag_if_it_exists`" + } + }, + { + "ruleId": "applic_CVE-2023-52355", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the following functions are called:\n\n- `TIFFRasterScanlineSize64()`\n- `TIFFRasterScanlineSize()`" + } + }, + { + "ruleId": "applic_CVE-2023-52356", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the following functions are called:\n\n- `TIFFReadRGBATileExt()` \n- `TIFFReadRGBATile()`" + } + }, + { + "ruleId": "applic_CVE-2023-5363", + "kind": "pass", + "message": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n- `EVP_EncryptInit_ex2`\n- `EVP_DecryptInit_ex2`\n- `EVP_CipherInit_ex2`" + } + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2023-6246", + "message": { + "text": "The vulnerable function `syslog` is called in a suid/guid file" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///usr/bin/chage" + }, + "region": { + "snippet": { + "text": "" + } + } + } + } + ] + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2023-6246", + "message": { + "text": "The vulnerable function `syslog` is called in a suid/guid file" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///usr/bin/chfn" + }, + "region": { + "snippet": { + "text": "" + } + } + } + } + ] + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2023-6246", + "message": { + "text": "The vulnerable function `syslog` is called in a suid/guid file" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///usr/bin/chsh" + }, + "region": { + "snippet": { + "text": "" + } + } + } + } + ] + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2023-6246", + "message": { + "text": "The vulnerable function `syslog` is called in a suid/guid file" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///usr/bin/expiry" + }, + "region": { + "snippet": { + "text": "" + } + } + } + } + ] + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2023-6246", + "message": { + "text": "The vulnerable function `syslog` is called in a suid/guid file" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///usr/bin/gpasswd" + }, + "region": { + "snippet": { + "text": "" + } + } + } + } + ] + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2023-6246", + "message": { + "text": "The vulnerable function `syslog` is called in a suid/guid file" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///usr/bin/newgrp" + }, + "region": { + "snippet": { + "text": "" + } + } + } + } + ] + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2023-6246", + "message": { + "text": "The vulnerable function `syslog` is called in a suid/guid file" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///usr/bin/passwd" + }, + "region": { + "snippet": { + "text": "" + } + } + } + } + ] + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2023-6246", + "message": { + "text": "The vulnerable function `syslog` is called in a suid/guid file" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///usr/bin/su" + }, + "region": { + "snippet": { + "text": "" + } + } + } + } + ] + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2023-6246", + "message": { + "text": "The vulnerable function `vsyslog` is called in a suid/guid file" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///usr/sbin/unix_chkpwd" + }, + "region": { + "snippet": { + "text": "" + } + } + } + } + ] + }, + { + "ruleId": "applic_CVE-2023-6879", + "kind": "pass", + "message": { + "text": "The scanner checks whether an encoding process is performed with the following requirements:\n\n* Using AV1 codec (`aom_codec_av1_cx()`).\n* Encoding (`aom_codec_encode()`)\n* Cleaning the memory at the end of the encoding process (`aom_codec_destroy()`).\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: `aom` is configured to use more than 1 thread. For example:\n```\naom_codec_enc_cfg_t cfg;\naom_codec_enc_config_default(iface, \u0026cfg, AOM_USAGE_GOOD_QUALITY));\ncfg.g_threads = 4;\n```" + } + }, + { + "ruleId": "applic_CVE-2024-0553", + "kind": "pass", + "message": { + "text": "The scanner checks if RSA decryption occurs by finding calls to any of the following functions:\n\n- `gnutls_privkey_decrypt_data`\n\n- `gnutls_privkey_decrypt_data2`\n\nAn additional condition (that the scanner does not currently check) is required for the CVE to be applicable: the RSA padding algorithm needs to be `PKCS#1`. `key-\u003epk_algorithm` needs to be equal to `GNUTLS_PK_RSA`." + } + }, + { + "ruleId": "applic_CVE-2024-0567", + "kind": "pass", + "message": { + "text": "The scanner checks if any of the following vulnerable functions are called:\n\n- `gnutls_pcert_import_x509_list`\n\n- `gnutls_certificate_set_x509_key`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_mem`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_file`\n\n- `gnutls_privkey_import_url`\n\n- `gnutls_privkey_import_pkcs11_url`\n\n- `gnutls_read_key_file`\n\n- `gnutls_certificate_set_rawpk_key_file`\n\n- `gnutls_certificate_set_x509_key_file2`\n\n- `gnutls_certificate_set_x509_key_file`\n\n- `gnutls_pcert_list_import_x509_file`\n\n- `gnutls_certificate_set_x509_key_mem2`\n\n- `gnutls_certificate_set_x509_key_mem`\n\n- `gnutls_x509_crt_list_import`\n\n- `gnutls_pcert_list_import_x509_raw`\n\n- `gnutls_session_channel_binding`\n\n- `gnutls_x509_crt_list_import2`\n\n- `gnutls_x509_trust_list_add_trust_mem`\n\n- `gnutls_x509_trust_list_add_system_trust`\n\n- `gnutls_certificate_set_x509_system_trust`\n\n- `gnutls_certificate_set_x509_crl_mem`\n\n- `gnutls_certificate_set_x509_trust_mem`\n\n- `gnutls_x509_trust_list_add_trust_file`\n\n- `gnutls_certificate_set_x509_crl_file`\n\n- `gnutls_certificate_set_x509_trust_file`\n\n- `gnutls_x509_trust_list_add_trust_dir`\n\n- `gnutls_certificate_set_x509_trust_dir`\n\n- `gnutls_x509_trust_list_remove_trust_mem`\n\n- `gnutls_x509_trust_list_remove_trust_file`\n\n- `gnutls_x509_trust_list_verify_crt2`\n\n- `gnutls_x509_cert_verify_peers`\n\n- `gnutls_certificate_verify_peers`\n\n- `gnutls_certificate_verify_peers2`\n\n- `gnutls_certificate_verify_peers3`\n\n- `gnutls_pkcs7_verify`\n\n- `gnutls_ocsp_resp_verify`\n\n- `gnutls_x509_trust_list_verify_crt`" + } + }, + { + "ruleId": "applic_CVE-2024-25062", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the following functions are called:\n\n* `xmlValidatePopElement()`\n* `xmlTextReaderClose()`\n* `xmlFreeTextReader() `\n* `xmlTextReaderRead()`\n* `xmlSchemaValidateDoc()`" + } + }, + { + "ruleId": "applic_CVE-2024-2961", + "kind": "pass", + "message": { + "text": "" + } + }, + { + "ruleId": "applic_CVE-2024-33600", + "kind": "pass", + "message": { + "text": "The scanner checks whether the `nscd` binary exists on the machine." + } + }, + { + "ruleId": "applic_CVE-2024-33599", + "kind": "pass", + "message": { + "text": "The scanner checks whether the `nscd` binary exists on the machine." + } + }, + { + "ruleId": "applic_CVE-2024-4741", + "kind": "pass", + "message": { + "text": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called." + } + }, + { + "ruleId": "applic_CVE-2023-49464", + "kind": "pass", + "message": { + "text": "The scanner checks for two conditions:\n\n1. The `libheif.so` binary was compiled with the vulnerable setting `-DWITH_UNCOMPRESSED_CODEC=ON`. \n\n2. Any of the following vulnerable functions are called:\n\n* `HeifContext::Image::get_luma_bits_per_pixel`\n* `HeifContext::decode_full_grid_image`\n* `HeifFile::get_luma_bits_per_pixel_from_configuration`\n* `UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci`\n* `heif_image_handle_get_luma_bits_per_pixel`" + } + }, + { + "ruleId": "applic_CVE-2024-6119", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`" + } + } + ] + } + ], + "secrets": [ + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Binary Secrets Scanner", + "rules": [ + { + "id": "REQ.SECRET.GENERIC.TEXT", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.TEXT" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.GENERIC.CODE", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.CODE" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "undetermined", + "conclusion": "private" + } + }, + { + "id": "REQ.SECRET.KEYS", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.KEYS" + }, + "fullDescription": { + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + "help": { + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + "properties": { + "applicability": "undetermined", + "conclusion": "private" + } + }, + { + "id": "REQ.CRED.PUBLIC-ONLY", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.CRED.PUBLIC-ONLY" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "help": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "undetermined", + "conclusion": "private" + } + }, + { + "id": "REQ.SECRET.GENERIC.URL", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.URL" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "undetermined", + "conclusion": "private" + } + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1725978580-3584350251/Secrets_1725978603/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1725978503-2625964325/image.tar" + } + } + ], + "results": [] + } + ] + } + } + ] + } \ No newline at end of file diff --git a/tests/testdata/output/dockerscan/docker_sarif.json b/tests/testdata/output/dockerscan/docker_sarif.json new file mode 100644 index 00000000..e69de29b diff --git a/tests/testdata/output/dockerscan/docker_simple_json.json b/tests/testdata/output/dockerscan/docker_simple_json.json new file mode 100644 index 00000000..e69de29b diff --git a/tests/testdata/output/dockerscan/docker_summary.json b/tests/testdata/output/dockerscan/docker_summary.json new file mode 100644 index 00000000..8fa8d1ed --- /dev/null +++ b/tests/testdata/output/dockerscan/docker_summary.json @@ -0,0 +1,77 @@ +{ + "resultType": "docker_image", + "args": { + "base_jfrog_url": "https://tokyoshiftleft.jfrog.io/", + "docker_image": "nginx:latest" + }, + "summary": { + "scans": [ + { + "target": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1725978503-2625964325/image.tar", + "name": "nginx:latest", + "vulnerabilities": { + "sca": { + "scan_ids": [ + "f1ca2a08-1d7b-4194-72be-7b84afc51fac" + ], + "security": { + "Critical": { + "Not Applicable": 4, + "Not Covered": 3 + }, + "High": { + "Applicable": 1, + "Not Applicable": 19, + "Not Covered": 5, + "Undetermined": 2 + }, + "Low": { + "Not Applicable": 5, + "Not Covered": 47 + }, + "Medium": { + "Not Applicable": 3, + "Not Covered": 28 + }, + "Unknown": { + "Applicable": 1, + "Not Applicable": 5, + "Not Covered": 21, + "Undetermined": 1 + } + } + }, + "iac": {}, + "secrets": {}, + "sast": {} + }, + "violations": { + "watches": [ + "Security_watch_1" + ], + "sca": { + "scan_ids": [ + "f1ca2a08-1d7b-4194-72be-7b84afc51fac" + ], + "security": { + "Critical": { + "Not Applicable": 4, + "Not Covered": 3 + }, + "High": { + "Applicable": 1, + "Not Applicable": 19, + "Not Covered": 5, + "Undetermined": 2 + }, + "Medium": { + "Not Applicable": 3, + "Not Covered": 28 + } + } + } + } + } + ] + } +} \ No newline at end of file diff --git a/utils/formats/sarifutils/sarifutils.go b/utils/formats/sarifutils/sarifutils.go index ad1a5f2c..6bc9144d 100644 --- a/utils/formats/sarifutils/sarifutils.go +++ b/utils/formats/sarifutils/sarifutils.go @@ -65,6 +65,51 @@ func ReadScanRunsFromFile(fileName string) (sarifRuns []*sarif.Run, err error) { return } +func CopyResult(result *sarif.Result) *sarif.Result { + copied := &sarif.Result{ + RuleID: result.RuleID, + RuleIndex: result.RuleIndex, + Kind: result.Kind, + Fingerprints: result.Fingerprints, + CodeFlows: result.CodeFlows, + Level: result.Level, + Message: result.Message, + PropertyBag: result.PropertyBag, + } + for _, location := range result.Locations { + copied.Locations = append(copied.Locations, CopyLocation(location)) + } + return copied +} + +func CopyLocation(location *sarif.Location) *sarif.Location { + copied := &sarif.Location{ + PhysicalLocation: &sarif.PhysicalLocation{ + ArtifactLocation: &sarif.ArtifactLocation{ + URI: location.PhysicalLocation.ArtifactLocation.URI, + }, + Region: &sarif.Region{ + StartLine: location.PhysicalLocation.Region.StartLine, + StartColumn: location.PhysicalLocation.Region.StartColumn, + EndLine: location.PhysicalLocation.Region.EndLine, + EndColumn: location.PhysicalLocation.Region.EndColumn, + Snippet: location.PhysicalLocation.Region.Snippet, + }, + }, + } + copied.Properties = location.Properties + for _, logicalLocation := range location.LogicalLocations { + copied.LogicalLocations = append(copied.LogicalLocations, &sarif.LogicalLocation{ + Name: logicalLocation.Name, + FullyQualifiedName: logicalLocation.FullyQualifiedName, + DecoratedName: logicalLocation.DecoratedName, + Kind: logicalLocation.Kind, + PropertyBag: logicalLocation.PropertyBag, + }) + } + return copied +} + func AggregateMultipleRunsIntoSingle(runs []*sarif.Run, destination *sarif.Run) { if len(runs) == 0 { return diff --git a/utils/formats/table.go b/utils/formats/table.go index 29e8f41f..cbe47f5b 100644 --- a/utils/formats/table.go +++ b/utils/formats/table.go @@ -6,6 +6,7 @@ package formats type ResultsTables struct { SecurityVulnerabilitiesTable []vulnerabilityTableRow + SecurityViolationsTable []vulnerabilityTableRow LicensesTable []licenseTableRow LicenseViolationsTable []licenseViolationTableRow OperationalRiskViolationsTable []operationalRiskViolationTableRow diff --git a/utils/results/common.go b/utils/results/common.go index 2399e5d9..75b34cf3 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -466,7 +466,7 @@ func GetCveApplicabilityField(cveId string, applicabilityScanResults []*sarif.Ru case len(applicability.Evidence) == 0: applicability.Status = string(jasutils.NotApplicable) default: - applicability.Status = string(jasutils.Applicable) + applicability.Status = string(jasutils.NotCovered) } return &applicability } diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index 779961c2..dd7e47f9 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -51,6 +51,7 @@ type CmdResultsSarifConverter struct { // Current stream parse cache information current *sarif.Report scaCurrentRun *sarif.Run + currentTarget results.ScanTarget parsedScaKeys *datastructures.Set[string] // General information on the current command results entitledForJas bool @@ -93,11 +94,12 @@ func (sc *CmdResultsSarifConverter) ParseNewTargetResults(target results.ScanTar } if sc.scaCurrentRun != nil { // Flush the current run - sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.ScaScan, target, sc.scaCurrentRun)...) + sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.ScaScan, sc.currentTarget, sc.scaCurrentRun)...) } + sc.currentTarget = target if sc.hasViolationContext || sc.includeVulnerabilities { // Create Sca Run if requested to parse all vulnerabilities/violations to it - sc.scaCurrentRun = sc.createScaRun(target, len(errors)) + sc.scaCurrentRun = sc.createScaRun(sc.currentTarget, len(errors)) sc.parsedScaKeys = datastructures.MakeSet[string]() } return @@ -499,7 +501,7 @@ func patchResults(commandType utils.CommandType, subScanType utils.SubScanType, } sarifutils.SetResultMsgMarkdown(markdown, result) // For Binary scans, override the physical location if applicable (after data already used for markdown) - convertBinaryPhysicalLocations(commandType, run, result) + result = convertBinaryPhysicalLocations(commandType, run, result) // Calculate the fingerprints if not exists if !sarifutils.IsFingerprintsExists(result) { if err := calculateResultFingerprints(commandType, run, result); err != nil { @@ -512,7 +514,7 @@ func patchResults(commandType utils.CommandType, subScanType utils.SubScanType, return patched } -func convertBinaryPhysicalLocations(commandType utils.CommandType, run *sarif.Run, result *sarif.Result) { +func convertBinaryPhysicalLocations(commandType utils.CommandType, run *sarif.Run, result *sarif.Result) *sarif.Result { if patchedLocation := getPatchedBinaryLocation(commandType, run); patchedLocation != "" { for _, location := range result.Locations { // Patch the location - Reset the uri and region diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go index 645e62ff..727418fb 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go @@ -545,6 +545,11 @@ func sortResults(simpleJsonResults *formats.SimpleJsonResults) { if len(simpleJsonResults.Vulnerabilities) > 0 { sortVulnerabilityOrViolationRows(simpleJsonResults.Vulnerabilities) } + if len(simpleJsonResults.Licenses) > 0 { + sort.Slice(simpleJsonResults.Licenses, func(i, j int) bool { + return simpleJsonResults.Licenses[i].LicenseKey < simpleJsonResults.Licenses[j].LicenseKey + }) + } if len(simpleJsonResults.LicensesViolations) > 0 { sort.Slice(simpleJsonResults.LicensesViolations, func(i, j int) bool { return simpleJsonResults.LicensesViolations[i].SeverityNumValue > simpleJsonResults.LicensesViolations[j].SeverityNumValue @@ -587,7 +592,7 @@ func sortVulnerabilityOrViolationRows(rows []formats.VulnerabilityOrViolationRow // getJfrogResearchPriority returns the score of JFrog Research Severity. // If there is no such severity will return the normal severity score. -// When vulnerability with JFrog Reasearch to a vulnerability without we'll compare the JFrog Research Severity to the normal severity +// When vulnerability with JFrog Research to a vulnerability without we'll compare the JFrog Research Severity to the normal severity func getJfrogResearchPriority(vulnerabilityOrViolation formats.VulnerabilityOrViolationRow) int { if vulnerabilityOrViolation.JfrogResearchInformation == nil { return vulnerabilityOrViolation.SeverityNumValue diff --git a/utils/results/conversion/tableparser/tableparser.go b/utils/results/conversion/tableparser/tableparser.go index 95e5777e..fe2925f2 100644 --- a/utils/results/conversion/tableparser/tableparser.go +++ b/utils/results/conversion/tableparser/tableparser.go @@ -28,6 +28,7 @@ func (tc *CmdResultsTableConverter) Get() (formats.ResultsTables, error) { } return formats.ResultsTables{ SecurityVulnerabilitiesTable: formats.ConvertToVulnerabilityTableRow(simpleJsonFormat.Vulnerabilities), + SecurityViolationsTable: formats.ConvertToVulnerabilityTableRow(simpleJsonFormat.SecurityViolations), LicenseViolationsTable: formats.ConvertToLicenseViolationTableRow(simpleJsonFormat.LicensesViolations), OperationalRiskViolationsTable: formats.ConvertToOperationalRiskViolationTableRow(simpleJsonFormat.OperationalRiskViolations), SecretsTable: formats.ConvertToSecretsTableRow(simpleJsonFormat.Secrets), diff --git a/utils/results/output/resultwriter.go b/utils/results/output/resultwriter.go index e887310b..fe4243ec 100644 --- a/utils/results/output/resultwriter.go +++ b/utils/results/output/resultwriter.go @@ -273,7 +273,7 @@ func PrintViolationsTable(tables formats.ResultsTables, scanType services.ScanTy // Space before the tables log.Output() if scanType == services.Binary { - err = coreutils.PrintTable(formats.ConvertSecurityTableRowToScanTableRow(tables.SecurityVulnerabilitiesTable), "Security Violations", "No security violations were found", printExtended) + err = coreutils.PrintTable(formats.ConvertSecurityTableRowToScanTableRow(tables.SecurityViolationsTable), "Security Violations", "No security violations were found", printExtended) if err != nil { return err } @@ -285,7 +285,7 @@ func PrintViolationsTable(tables formats.ResultsTables, scanType services.ScanTy return coreutils.PrintTable(formats.ConvertOperationalRiskTableRowToScanTableRow(tables.OperationalRiskViolationsTable), "Operational Risk Violations", "No operational risk violations were found", printExtended) } } else { - err = coreutils.PrintTable(tables.SecurityVulnerabilitiesTable, "Security Violations", "No security violations were found", printExtended) + err = coreutils.PrintTable(tables.SecurityViolationsTable, "Security Violations", "No security violations were found", printExtended) if err != nil { return err } diff --git a/utils/results/results.go b/utils/results/results.go index a1ee4b3a..ddecca7e 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -116,7 +116,9 @@ func (r *SecurityCommandResults) GetJasScansResults(scanType jasutils.JasScanTyp func (r *SecurityCommandResults) GetErrors() (err error) { err = r.Error for _, target := range r.Targets { - err = errors.Join(err, fmt.Errorf("target '%s' errors:\n%s", target.String(), target.GetErrors())) + if targetErr := target.GetErrors(); targetErr != nil { + err = errors.Join(err, fmt.Errorf("target '%s' errors:\n%s", target.String(), targetErr)) + } } return } @@ -223,7 +225,6 @@ func (sr *TargetResults) GetTechnologies() []techutils.Technology { } for _, scaResult := range sr.ScaResults.XrayResults { for _, vulnerability := range scaResult.Vulnerabilities { - // if tech, ok := techutils.Technology(vulnerability.Technology); ok { if tech := techutils.Technology(strings.ToLower(vulnerability.Technology)); tech != "" { technologiesSet.Add(tech) } diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index a5ea3fb3..8e0d4bd6 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -15,6 +15,7 @@ import ( const ( SastToolName = "USAF" IacToolName = "JFrog Terraform scanner" + // #nosec G101 -- Not credentials. SecretsToolName = "JFrog Secrets scanner" ) From 2840382da7826edd9f4e7096bec30158aed23b4e Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 15 Sep 2024 09:27:22 +0300 Subject: [PATCH 55/82] fixing bugs adding docker tests --- commands/scan/dockerscan.go | 5 +- commands/scan/scan.go | 23 +- jas/secrets/secretsscanner.go | 2 +- .../sast-scan/contains-sast-violations.sarif | 62 +- .../other/sast-scan/no-violations.sarif | 4 +- .../testdata/output/audit/audit_results.json | 22 +- .../output/dockerscan/docker_results.json | 17047 +--------------- .../output/dockerscan/docker_sarif.json | 778 + .../output/dockerscan/docker_simple_json.json | 826 + .../output/dockerscan/docker_summary.json | 116 +- .../projects/jas/jas-config/sast/result.sarif | 46 +- .../projects/jas/jas/sast/result.sarif | 46 +- utils/formats/sarifutils/sarifutils.go | 167 +- utils/formats/sarifutils/sarifutils_test.go | 6 +- utils/formats/sarifutils/test_sarifutils.go | 9 +- utils/results/common.go | 21 +- utils/results/conversion/convertor.go | 8 +- utils/results/conversion/convertor_test.go | 43 +- .../conversion/sarifparser/sarifparser.go | 66 +- .../sarifparser/sarifparser_test.go | 8 +- .../simplejsonparser/simplejsonparser.go | 4 +- .../conversion/tableparser/tableparser.go | 2 +- utils/results/output/resultwriter.go | 42 +- utils/validations/test_validate_sarif.go | 4 +- 24 files changed, 2857 insertions(+), 16500 deletions(-) diff --git a/commands/scan/dockerscan.go b/commands/scan/dockerscan.go index ec619090..a2f23c42 100644 --- a/commands/scan/dockerscan.go +++ b/commands/scan/dockerscan.go @@ -87,7 +87,7 @@ func (dsc *DockerScanCommand) Run() (err error) { Pattern(imageTarPath). Target(dsc.targetRepoPath). BuildSpec()).SetThreads(1) - dsc.ScanCommand.SetRunJasScans(true) + dsc.ScanCommand.SetTargetNameOverride(dsc.imageTag).SetRunJasScans(true) err = dsc.setCredentialEnvsForIndexerApp() if err != nil { return errorutils.CheckError(err) @@ -102,9 +102,6 @@ func (dsc *DockerScanCommand) Run() (err error) { if scanResults == nil { return } - for _, scan := range scanResults.Targets { - scan.Name = dsc.imageTag - } dsc.analyticsMetricsService.UpdateGeneralEvent(dsc.analyticsMetricsService.CreateXscAnalyticsGeneralEventFinalizeFromAuditResults(scanResults)) return dsc.recordResults(scanResults) }) diff --git a/commands/scan/scan.go b/commands/scan/scan.go index e7335788..74292bb1 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -72,6 +72,7 @@ type ScanCommand struct { progress ioUtils.ProgressMgr // JAS is only supported for Docker images. commandSupportsJAS bool + targetNameOverride string analyticsMetricsService *xsc.AnalyticsMetricsService } @@ -90,6 +91,11 @@ func (scanCmd *ScanCommand) SetRunJasScans(run bool) *ScanCommand { return scanCmd } +func (scanCmd *ScanCommand) SetTargetNameOverride(targetName string) *ScanCommand { + scanCmd.targetNameOverride = targetName + return scanCmd +} + func (scanCmd *ScanCommand) SetProgress(progress ioUtils.ProgressMgr) { scanCmd.progress = progress } @@ -305,10 +311,6 @@ func (scanCmd *ScanCommand) RunAndRecordResults(cmdType utils.CommandType, recor err = errors.New("failed while trying to get Analyzer Manager: " + err.Error()) } - if err = recordResFunc(cmdResults); err != nil { - return err - } - if err = output.NewResultsWriter(cmdResults). SetOutputFormat(scanCmd.outputFormat). SetHasViolationContext(scanCmd.hasViolationContext()). @@ -320,6 +322,10 @@ func (scanCmd *ScanCommand) RunAndRecordResults(cmdType utils.CommandType, recor return } + if err = recordResFunc(cmdResults); err != nil { + return err + } + // If includeVulnerabilities is false it means that context was provided, so we need to check for build violations. // If user provided --fail=false, don't fail the build. if scanCmd.fail && !scanCmd.includeVulnerabilities { @@ -361,12 +367,19 @@ func (scanCmd *ScanCommand) prepareScanTasks(fileProducer, indexedFileProducer p }() } +func (scanCmd *ScanCommand) getBinaryTargetName(binaryPath string) string { + if scanCmd.targetNameOverride != "" { + return scanCmd.targetNameOverride + } + return filepath.Base(binaryPath) +} + func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, cmdResults *results.SecurityCommandResults, indexedFileProducer parallel.Runner, jasFileProducerConsumer *utils.SecurityParallelRunner) FileContext { return func(filePath string) parallel.TaskFunc { return func(threadId int) (err error) { logMsgPrefix := clientutils.GetLogMsgPrefix(threadId, false) // Create a scan target for the file. - targetResults := cmdResults.NewScanResults(results.ScanTarget{Target: filePath, Name: filepath.Base(filePath)}) + targetResults := cmdResults.NewScanResults(results.ScanTarget{Target: filePath, Name: scanCmd.getBinaryTargetName(filePath)}) log.Info(logMsgPrefix+"Indexing file:", targetResults.Target) if scanCmd.progress != nil { scanCmd.progress.SetHeadlineMsg("Indexing file: " + targetResults.Name + " 🗄") diff --git a/jas/secrets/secretsscanner.go b/jas/secrets/secretsscanner.go index 347833e6..f744d5bd 100644 --- a/jas/secrets/secretsscanner.go +++ b/jas/secrets/secretsscanner.go @@ -127,7 +127,7 @@ func processSecretScanRuns(sarifRuns []*sarif.Run) []*sarif.Run { // Hide discovered secrets value for _, secretResult := range secretRun.Results { for _, location := range secretResult.Locations { - sarifutils.SetLocationSnippet(location, maskSecret(sarifutils.GetLocationSnippet(location))) + sarifutils.SetLocationSnippet(location, maskSecret(sarifutils.GetLocationSnippetText(location))) } } } diff --git a/tests/testdata/other/sast-scan/contains-sast-violations.sarif b/tests/testdata/other/sast-scan/contains-sast-violations.sarif index d8b3c02e..f6251a23 100644 --- a/tests/testdata/other/sast-scan/contains-sast-violations.sarif +++ b/tests/testdata/other/sast-scan/contains-sast-violations.sarif @@ -165,12 +165,12 @@ { "executionSuccessful": true, "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", + "/users/user/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", "scan", "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1693477603-3697552683/results.sarif" ], "workingDirectory": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat" + "uri": "file:///Users/user/proj" } } ], @@ -193,7 +193,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 28, @@ -216,7 +216,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 32, @@ -239,7 +239,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 44, @@ -262,7 +262,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 13, @@ -285,7 +285,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 31, @@ -308,7 +308,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 31, @@ -331,7 +331,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 10, @@ -354,7 +354,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 39, @@ -377,7 +377,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/__init__.py" + "uri": "file:///Users/user/proj/flask_webgoat/__init__.py" }, "region": { "endColumn": 19, @@ -400,7 +400,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/__init__.py" + "uri": "file:///Users/user/proj/flask_webgoat/__init__.py" }, "region": { "endColumn": 49, @@ -429,7 +429,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/__init__.py" + "uri": "file:///Users/user/proj/flask_webgoat/__init__.py" }, "region": { "endColumn": 49, @@ -463,7 +463,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 28, @@ -486,7 +486,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 32, @@ -509,7 +509,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 44, @@ -532,7 +532,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 13, @@ -555,7 +555,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 31, @@ -578,7 +578,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 31, @@ -601,7 +601,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 10, @@ -624,7 +624,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 39, @@ -647,7 +647,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/__init__.py" + "uri": "file:///Users/user/proj/flask_webgoat/__init__.py" }, "region": { "endColumn": 19, @@ -670,7 +670,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/__init__.py" + "uri": "file:///Users/user/proj/flask_webgoat/__init__.py" }, "region": { "endColumn": 49, @@ -699,7 +699,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/__init__.py" + "uri": "file:///Users/user/proj/flask_webgoat/__init__.py" }, "region": { "endColumn": 49, @@ -733,7 +733,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 23, @@ -756,7 +756,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 27, @@ -779,7 +779,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 34, @@ -802,7 +802,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 8, @@ -825,7 +825,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 29, @@ -854,7 +854,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/flask_webgoat/auth.py" + "uri": "file:///Users/user/proj/flask_webgoat/auth.py" }, "region": { "endColumn": 29, @@ -883,7 +883,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/flask-webgoat/run.py" + "uri": "file:///Users/user/proj/run.py" }, "region": { "endColumn": 24, diff --git a/tests/testdata/other/sast-scan/no-violations.sarif b/tests/testdata/other/sast-scan/no-violations.sarif index ed129e6e..f9534d60 100644 --- a/tests/testdata/other/sast-scan/no-violations.sarif +++ b/tests/testdata/other/sast-scan/no-violations.sarif @@ -11,12 +11,12 @@ { "executionSuccessful": true, "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", + "/users/user/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", "scan", "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1693477603-3697552683/results.sarif" ], "workingDirectory": { - "uri": "file:///Users/assafa/Documents/code/terraform" + "uri": "file:///Users/user/testdata/terraform" } } ], diff --git a/tests/testdata/output/audit/audit_results.json b/tests/testdata/output/audit/audit_results.json index e64adb15..65811aa2 100644 --- a/tests/testdata/output/audit/audit_results.json +++ b/tests/testdata/output/audit/audit_results.json @@ -66,7 +66,7 @@ "https://github.com/lodash/lodash/issues/4874", "https://github.com/lodash/lodash/wiki/Changelog#v41719" ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-114089\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "ignore_url": "https://platform.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-114089\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", "extended_information": { "short_description": "Prototype pollution in lodash object merging and zipping functions leads to code injection.", "full_description": "[lodash](https://lodash.com/) is a JavaScript library which provides utility functions for common programming tasks.\n\nJavaScript frontend and Node.js-based backend applications that merge or zip objects using the lodash functions `mergeWith`, `merge` and `zipObjectDeep` are vulnerable to [prototype pollution](https://medium.com/node-modules/what-is-prototype-pollution-and-why-is-it-such-a-big-deal-2dd8d89a93c) if one or more of the objects it receives as arguments are obtained from user input. \nAn attacker controlling this input given to the vulnerable functions can inject properties to JavaScript special objects such as [Object.prototype](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes) from which all JavaScript objects inherit properties and methods. Any change on `Object.prototype` properties will then propagate through the prototype chain inheritance to all of the objects in a JavaScript application. This in turn would allow an attacker to add new properties or modify existing properties which will have application specific implications that could lead to DoS (denial of service), authentication bypass, privilege escalation and even RCE (remote code execution) in [some cases](https://youtu.be/LUsiFV3dsK8?t=1152). \nAs an example for privilege escalation, consider a JavaScript application that has a `user` object which has a Boolean property of `user.isAdmin` which is used to decide which actions the user may take. If an attacker can modify or add the `isAdmin` property through prototype pollution, it can escalate the privileges of its own user to those of an admin. \nAs exploitation is usually application specific, successful exploitation is much more likely if an attacker have access to the JavaScript application code. As such, frontend applications are more vulnerable to this vulnerability than Node.js backend applications.", @@ -127,7 +127,7 @@ "https://security.netapp.com/advisory/ntap-20190919-0004/", "https://github.com/lodash/lodash/commit/d8e069cc3410082e44eb18fcf8e7f3d08ebe1d4a" ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-72918\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + "ignore_url": "https://platform.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-72918\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" }, { "summary": "Express.js minimalist web framework for node. Versions of Express.js prior to 4.19.0 and all pre-release alpha and beta versions of 5.0 are affected by an open redirect vulnerability using malformed URLs. When a user of Express performs a redirect using a user-provided URL Express performs an encode [using `encodeurl`](https://github.com/pillarjs/encodeurl) on the contents before passing it to the `location` header. This can cause malformed URLs to be evaluated in unexpected ways by common redirect allow list implementations in Express applications, leading to an Open Redirect via bypass of a properly implemented allow list. The main method impacted is `res.location()` but this is also called from within `res.redirect()`. The vulnerability is fixed in 4.19.2 and 5.0.0-beta.3.", @@ -170,7 +170,7 @@ "https://nvd.nist.gov/vuln/detail/CVE-2024-29041", "https://github.com/expressjs/express/security/advisories/GHSA-rv95-896h-c2vc" ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-594935\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + "ignore_url": "https://platform.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-594935\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" }, { "summary": "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.", @@ -213,7 +213,7 @@ "https://security.netapp.com/advisory/ntap-20190919-0004", "https://hackerone.com/reports/380873" ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-75300\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "ignore_url": "https://platform.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-75300\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", "extended_information": { "short_description": "Insufficient input validation in the Lodash library leads to prototype pollution.", "full_description": "The [Lodash](https://lodash.com/) library is an open-source JavaScript project that simplifies operations on string, arrays, numbers, and other objects. It is widely used in connected devices. \n\nThe `merge`, `mergeWith`, and `defaultsDeep` methods in Lodash are vulnerable to [prototype pollution](https://shieldfy.io/security-wiki/prototype-pollution/introduction-to-prototype-pollution/). Attackers can exploit this vulnerability by specifying a crafted `sources` parameter to any of these methods, which can modify the prototype properties of the `Object`, `Function`, `Array`, `String`, `Number`, and `Boolean` objects. A public [exploit](https://hackerone.com/reports/380873) exists which performs the prototype pollution with an arbitrary key and value.\n\nThe library implementation has a bug in the `safeGet()` function in the `lodash.js` module that allows for adding or modifying `prototype` properties of various objects. The official [solution](https://github.com/lodash/lodash/commit/90e6199a161b6445b01454517b40ef65ebecd2ad) fixes the bug by explicitly forbidding the addition or modification of `prototype` properties.\n\nA related CVE (CVE-2018-3721) covers the same issue prior to Lodash version 4.17.5, but the fix for that was incomplete.", @@ -279,7 +279,7 @@ "https://github.com/mde/ejs", "https://security.netapp.com/advisory/ntap-20220804-0001/" ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-209002\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "ignore_url": "https://platform.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-209002\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", "extended_information": { "short_description": "Insufficient input validation in EJS enables attackers to perform template injection when attacker can control the rendering options.", "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to perform template injection on the `opts.outputFunctionName` variable, since the variable is injected into the template body without any escaping. Although it is unlikely that the attacker can directly control the `outputFunctionName` property, it is possible that it can be influenced in conjunction with a prototype pollution vulnerability.\n\nOnce template injection is achieved, the attacker can immediately perform remote code execution since the template engine (EJS) allows executing arbitrary JavaScript code.\n\nExample of a vulnerable Node.js application -\n```js\nconst express = require('express');\nconst bodyParser = require('body-parser');\nconst lodash = require('lodash');\nconst ejs = require('ejs');\n\nconst app = express();\n\napp\n .use(bodyParser.urlencoded({extended: true}))\n .use(bodyParser.json());\n\napp.set('views', './');\napp.set('view engine', 'ejs');\n\napp.get(\"/\", (req, res) =\u003e {\n res.render('index');\n});\n\napp.post(\"/\", (req, res) =\u003e {\n let data = {};\n let input = JSON.parse(req.body.content);\n lodash.defaultsDeep(data, input);\n res.json({message: \"OK\"});\n});\n\nlet server = app.listen(8086, '0.0.0.0', function() {\n console.log('Listening on port %d', server.address().port);\n});\n```\n\nExploiting the above example for RCE -\n`curl 127.0.0.1:8086 -v --data 'content={\"constructor\": {\"prototype\": {\"outputFunctionName\": \"a; return global.process.mainModule.constructor._load(\\\"child_process\\\").execSync(\\\"whoami\\\"); //\"}}}'\n`\n\nDue to the prototype pollution in the `lodash.defaultsDeep` call, an attacker can inject the `outputFunctionName` property with an arbitrary value. The chosen value executes an arbitrary process via the `child_process` module.", @@ -340,7 +340,7 @@ "https://github.com/advisories/GHSA-ghr5-ch3p-vcr6", "https://nvd.nist.gov/vuln/detail/CVE-2024-33883" ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-599735\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "ignore_url": "https://platform.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-599735\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", "extended_information": { "short_description": "Insufficient input validation in EJS may lead to prototype pollution.", "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as `EJS`, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nA prototype pollution gadget within the EJS template engine could potentially be leveraged by attackers to achieve remote code execution or DoS via prototype pollution.\n\n```\nfunction Template(text, opts) {\n opts = opts || utils.createNullProtoObjWherePossible();\n```\n\nWhen checking for the presence of a property within an object variable, the lookup scope isn't explicitly defined. In JavaScript, the absence of a defined lookup scope prompts a search up to the root prototype (`Object.prototype`). This could potentially be under the control of an attacker if another prototype pollution vulnerability is present within the application.\n\nIf the application server is using the EJS as the backend template engine, and there is another prototype pollution vulnerability in the application, then the attacker could leverage the found gadgets in the EJS template engine to escalate the prototype pollution to remote code execution or DoS.\n\nThe following code will execute a command on the server by polluting `opts.escapeFunction`:\n \n```\nconst express = require('express');\nconst app = express();\nconst port = 8008;\nconst ejs = require('ejs');\n\n// Set EJS as the view engine\napp.set('view engine', 'ejs');\n\napp.get('/', (req, res) =\u003e {\n \n const data = {title: 'Welcome', message: 'Hello'};\n\n // Sample EJS template string\n const templateString = `\u003chtml\u003e\u003chead\u003e\u003ctitle\u003e\u003c%= title %\u003e\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003ch1\u003e\u003c%= message %\u003e\u003c/h1\u003e\u003c/body\u003e\u003c/html\u003e`;\n\n const { exec } = require('child_process');\n\n function myFunc() {\n exec('bash -c \"echo 123\"', (error, stdout, stderr) =\u003e {\n if (error) {\n console.error(`exec error: ${error}`);\n return;\n }\n if (stderr){\n console.log(`stderr : ${stderr}`);\n return;\n }\n // Handle success\n console.log(`Command executed successfully. Output: ${stdout}`);\n });\n }\n\n const options = {client:false};\n\n Object.prototype.escapeFunction = myFunc;\n \n const compiledTemplate = ejs.compile(templateString, options);\n const renderedHtml = compiledTemplate(data);\n res.send(renderedHtml);\n});\n\n// Start the server\napp.listen(port, () =\u003e {\n console.log(`Server is running on http://localhost:${port}`);\n});\n```", @@ -395,7 +395,7 @@ "https://github.com/mde/ejs/issues/720", "https://github.com/mde/ejs/blob/main/SECURITY.md#out-of-scope-vulnerabilities" ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-520200\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "ignore_url": "https://platform.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-520200\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", "extended_information": { "short_description": "Insufficient input validation can lead to template injection in ejs when attackers can control both the rendered template and rendering options.", "full_description": "[Embedded JavaScript templates](https://github.com/mde/ejs), also known as EJS, is one of the most popular Node.js templating engines, which is compiled with the Express JS view system.\n\nWhen rendering views using EJS, it is possible to bypass ejs' template injection restrictions, by abusing the `closeDelimiter` rendering option, in the case when -\n1. The template itself can be partially controlled by the attacker\n2. The template rendering options can be fully controlled by the attacker\n\nThe vulnerability was **rightfully disputed** due to the fact that a vulnerable configuration is extremely unlikely to exist in any real-world setup. As such, the maintainers will not provide a fix for this (non-)issue.\n\nExample of a vulnerable application -\n```js\nconst express = require('express')\nconst app = express()\nconst port = 3000\n\napp.set('view engine', 'ejs');\n\napp.get('/page', (req,res) =\u003e {\n res.render('page', req.query); // OPTS (2nd parameter) IS ATTACKER-CONTROLLED\n})\n\napp.listen(port, () =\u003e {\n console.log(\"Example app listening on port ${port}\")\n})\n```\n\nContents of `page.ejs` (very unlikely to be attacker controlled) -\n```js\n%%1\");process.mainModule.require('child_process').execSync('calc');//\n```\n\nIn this case, sending `closeDelimiter` with the same malicious code that already exists at `page.ejs` will trigger the injection -\n`http://127.0.0.1:3000/page?settings[view%20options][closeDelimiter]=1\")%3bprocess.mainModule.require('child_process').execSync('calc')%3b//`", @@ -467,7 +467,7 @@ "https://github.com/advisories/GHSA-jf85-cpcp-j695", "https://nvd.nist.gov/vuln/detail/CVE-2019-10744" ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-85679\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "ignore_url": "https://platform.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-85679\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", "extended_information": { "short_description": "Insufficient input validation in lodash defaultsDeep() leads to prototype pollution.", "full_description": "[lodash](https://www.npmjs.com/package/lodash) is a modern JavaScript utility library delivering modularity, performance, \u0026 extras.\n\nThe function `defaultsDeep` was found to be vulnerable to prototype pollution, when accepting arbitrary source objects from untrusted input\n\nExample of code vulnerable to this issue - \n```js\nconst lodash = require('lodash'); \nconst evilsrc = {constructor: {prototype: {evilkey: \"evilvalue\"}}};\nlodash.defaultsDeep({}, evilsrc)\n```", @@ -532,7 +532,7 @@ "https://github.com/lodash/lodash/issues/3359", "https://github.com/lodash/lodash/commit/5c08f18d365b64063bfbfa686cbb97cdd6267347" ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-85049\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" + "ignore_url": "https://platform.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-85049\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" }, { "summary": "Lodash versions prior to 4.17.21 are vulnerable to Regular Expression Denial of Service (ReDoS) via the toNumber, trim and trimEnd functions.", @@ -586,7 +586,7 @@ "https://snyk.io/vuln/SNYK-JAVA-ORGFUJIONWEBJARS-1074896", "https://snyk.io/vuln/SNYK-JS-LODASH-1018905" ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-140562\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "ignore_url": "https://platform.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-140562\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", "extended_information": { "short_description": "ReDoS in lodash could lead to a denial of service when handling untrusted strings.", "full_description": "JavaScript-based applications that use [lodash](https://github.com/lodash/lodash) and specifically the [_.toNumber](https://lodash.com/docs/4.17.15#toNumber), [_.trim](https://lodash.com/docs/4.17.15#trim) and [_.trimEnd](https://lodash.com/docs/4.17.15#trimEnd) functions, could be vulnerable to DoS (Denial of Service) through a faulty regular expression that introduces a ReDoS (Regular Expression DoS) vulnerability. This vulnerability is only triggered if untrusted user input flows into these vulnerable functions and the attacker can supply arbitrary long strings (over 50kB) that contain whitespaces. \n\nOn a modern Core i7-based system, calling the vulnerable functions with a 50kB string could take between 2 to 3 seconds to execute and 4.5 minutes for a longer 500kB string. The fix improved the regular expression performance so it took only a few milliseconds on the same Core i7-based system. This vulnerability is easily exploitable as all is required is to build a string that triggers it as can be seen in this PoC reproducing code - \n\n```js\nvar untrusted_user_input_50k = \"a\" + ' '.repeat(50000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_50k); // should take a few seconds to run\nvar untrusted_user_input_500k = \"a\" + ' '.repeat(500000) + \"z\"; // assume this is provided over the network\nlo.trimEnd(untrusted_user_input_500k); // should take a few minutes to run\n```", @@ -657,7 +657,7 @@ "https://nvd.nist.gov/vuln/detail/CVE-2021-23337", "https://github.com/lodash/lodash/blob/ddfd9b11a0126db2302cb70ec9973b66baec0975/lodash.js#L14851" ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-140575\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", + "ignore_url": "https://platform.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=711851ce-68c4-4dfd-7afb-c29737ebcb96\u0026issue_id=XRAY-140575\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", "extended_information": { "short_description": "Improper sanitization in the lodash template function leads to JavaScript code injection through the options argument.", "full_description": "JavaScript-based applications (both frontend and backend) that use the [template function](https://lodash.com/docs/4.17.15#template) -`_.template([string=''], [options={}])` from the [lodash](https://lodash.com/) utility library and provide the `options` argument (specifically the `variable` option) from untrusted user input, are vulnerable to JavaScript code injection. This issue can be easily exploited, and an exploitation example is [publicly available](https://github.com/lodash/lodash/commit/3469357cff396a26c363f8c1b5a91dde28ba4b1c#diff-a561630bb56b82342bc66697aee2ad96efddcbc9d150665abd6fb7ecb7c0ab2fR22303) in the fix tests that was introduced in version 4.17.21 - \n```js\nlodash.template('', { variable: '){console.log(process.env)}; with(obj' })()\n```", diff --git a/tests/testdata/output/dockerscan/docker_results.json b/tests/testdata/output/dockerscan/docker_results.json index e5958783..0ffdd2a0 100644 --- a/tests/testdata/output/dockerscan/docker_results.json +++ b/tests/testdata/output/dockerscan/docker_results.json @@ -1,16278 +1,909 @@ { - "xray_version": "3.104.8", - "jas_entitled": true, - "command_type": "docker_image", - "targets": [ - { - "target": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1725978503-2625964325/image.tar", - "name": "nginx:latest", - "technology": "oci", - "sca_scans": { - "xray_scan": [ - { - "scan_id": "f1ca2a08-1d7b-4194-72be-7b84afc51fac", - "violations": [ - { - "summary": "loadImage() in tools/tiffcrop.c in LibTIFF through 4.5.0 has a heap-based use after free via a crafted TIFF image.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-522607", - "cves": [ - { - "cve": "CVE-2023-26965", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-26965", - "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", - "https://security.netapp.com/advisory/ntap-20230706-0009/", - "https://gitlab.com/libtiff/libtiff/-/merge_requests/472" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-522607\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "Use after free in libtiff's Tiffcrop may lead to code execution when parsing crafted images.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "Published PoC demonstrates crashing the tiffcrop CLI utility. Note that crashing tiffcrop has no security impact, since it is a forked CLI utility (will not crash parent process)." - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Although a crashing PoC is available, exploiting the vulnerability for remote code execution is currently only theoretically possible, and actual exploitation has not been demonstrated. Only some cases of use-after-free can be exploited for RCE.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker must be able to upload a crafted TIFF image, which will then be processed by the `tiffcrop` CLI tool, for example -\n```bash\ntiffcrop -z 12,50,12,99:112,150,112,199 -e divided attacker_image.tiff output.tiff\n```", - "is_positive": true - } - ] - } - }, - { - "summary": "An out-of-memory flaw was found in libtiff that could be triggered by passing a crafted tiff file to the TIFFRasterScanlineSize64() API. This flaw allows a remote attacker to cause a denial of service via a crafted input with a size smaller than 379 KB.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-589394", - "cves": [ - { - "cve": "CVE-2023-52355", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://gitlab.com/libtiff/libtiff/-/issues/621", - "https://security-tracker.debian.org/tracker/CVE-2023-52355", - "https://bugzilla.redhat.com/show_bug.cgi?id=2251326", - "https://access.redhat.com/security/cve/CVE-2023-52355" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589394\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "Unbounded resource consumption in libtiff may lead to denial of service when parsing a crafted tiff file.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "PoC is included in the git issue discussing the problem." - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS attack complexity does not reflect the contextual prerequisites required to exploit the vulnerability.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "To exploit the vulnerability, the attacker must be able to upload a tiff file whose size will get checked by the vulnerable `TIFFRasterScanlineSize64()` function, and allocate memory (without any limitations) based on the results.", - "is_positive": true - } - ], - "remediation": "##### Development mitigations\n\nAs a workaround, users could implement checks, or use `TIFFOpenOptionsSetMaxSingleMemAlloc()`, to reject files that they consider to consume too many resources for their use case. For example -\n```\n// Allow 1MB single mem alloc\nTIFFOpenOptionsSetMaxSingleMemAlloc(\u0026opts, 1*1024*1024);\n```" - } - }, - { - "summary": "Integer overflow in libaom internal function img_alloc_helper can lead to heap buffer overflow. This function can be reached via 3 callers:\n\n\n * Calling aom_img_alloc() with a large value of the d_w, d_h, or align parameter may result in integer overflows in the calculations of buffer sizes and offsets and some fields of the returned aom_image_t struct may be invalid.\n * Calling aom_img_wrap() with a large value of the d_w, d_h, or align parameter may result in integer overflows in the calculations of buffer sizes and offsets and some fields of the returned aom_image_t struct may be invalid.\n * Calling aom_img_alloc_with_border() with a large value of the d_w, d_h, align, size_align, or border parameter may result in integer overflows in the calculations of buffer sizes and offsets and some fields of the returned aom_image_t struct may be invalid.", - "severity": "Critical", - "type": "security", - "components": { - "deb://debian:bookworm:libaom3:3.6.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libaom3:3.6.0-1", - "full_path": "libaom3:3.6.0-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-604193", - "cves": [ - { - "cve": "CVE-2024-5171", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-5171", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/6HYUEHZ35ZPY2EONVZCGO6LPT3AMLZCP/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/U5NRNCEYS246CYGOR32MF7OGKWOWER22/", - "https://issues.chromium.org/issues/332382766" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-604193\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "An integer overflow in libaom may lead to remote code execution when parsing malicious video data.", - "full_description": "[Libaom](https://aomedia.googlesource.com/aom/) is the reference encoder and decoder library for the `AV1` video codec. AV1 (AOMedia Video 1) is an open, royalty-free video coding format designed for video transmissions over the Internet. It was developed by the Alliance for Open Media (AOMedia), a consortium that includes firms like Google, Cisco, Microsoft, Mozilla, and Netflix.\nThe `aom` in libaom stands for `Alliance for Open Media`, and the library serves as a standard reference codebase that can be used to implement AV1 compression and decompression.\n\nProviding large values as the arguments to the `img_alloc_helper()` function, may lead to an integer overflow and a subsequent heap buffer overflow, which may lead to remote code execution.\n\n`img_alloc_helper()` function is an internal function that is used to allocate memory for an `aom_image_t` structure and its associated image data. This function is very useful when you need to manually create an image buffer that can then be used with the AOM codec for various operations like encoding or decoding.\n\nThe vulnerability cannot be exploited directly by calling `img_alloc_helper()` because it is an internal function. \n\nAlthough integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.\n\nTo exploit this vulnerability the following functions can be called with excessively large values as parameters:\n\n* `aom_img_alloc()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_wrap()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_alloc_with_border()` with a large value of the d_w, d_h, align, size_align, or border parameters.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "The published exploit demonstrates DoS." - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Although integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "The highest potential impact of this issue is severe (Remote Code Execution). Although no such impact has been demonstrated in practice." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "An attacker would need to find input propagating into the libaom encoding or decoding operations.", - "is_positive": true - } - ], - "remediation": "##### Development mitigations\n\nMake sure the following functions don't accept excessively large values as arguments to the following functions:\n\n* `aom_img_alloc()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_wrap()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_alloc_with_border()` with a large value of the d_w, d_h, align, size_align, or border parameters." - } - }, - { - "summary": "In MIT Kerberos 5 (aka krb5) before 1.21.3, an attacker can cause invalid memory reads during GSS message token handling by sending message tokens with invalid length fields.", - "severity": "Critical", - "type": "security", - "components": { - "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", - "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", - "full_path": "libk5crypto3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", - "full_path": "libkrb5-3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", - "full_path": "libkrb5support0:1.20.1-2+deb12u1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-607813", - "cves": [ - { - "cve": "CVE-2024-37371", - "cvss_v3_score": "9.1", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H" - } - ], - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-37371", - "https://web.mit.edu/kerberos/www/advisories/", - "https://github.com/krb5/krb5/commit/55fbf435edbe2e92dd8101669b1ce7144bc96fef" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-607813\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Libde265 v1.0.11 was discovered to contain a segmentation violation via the function decoder_context::process_slice_segment_header at decctx.cc.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-427847", - "cves": [ - { - "cve": "CVE-2023-27102", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://github.com/strukturag/libde265/issues/393", - "https://security-tracker.debian.org/tracker/CVE-2023-27102", - "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-427847\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the function find_exif_tag at /libheif/exif.cc.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libheif1:1.15.1-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", - "full_path": "libheif1:1.15.1-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-540355", - "cves": [ - { - "cve": "CVE-2023-49463", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://github.com/strukturag/libheif/issues/1042", - "https://github.com/strukturag/libheif", - "https://security-tracker.debian.org/tracker/CVE-2023-49463" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540355\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "An integer overflow in libheif leads to denial of service.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS score does not reflect the context dependent exploitation of this vulnerability.", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "A proof-of-concept was published along with the vulnerability via (GitHub)[https://github.com/strukturag/libheif/issues/1042]." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "To successfully exploit this vulnerability an attacker needs to find a way to propagate input into the vulnerable functions `modify_exif_tag_if_it_exists(unsigned char*, unsigned int, unsigned short, unsigned short)` or `read_exif_orientation_tag(unsigned char const*, unsigned int)`.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Successful exploitation of this vulnerability leads to denial of service." - } - ] - } - }, - { - "summary": "A vulnerability was found that the response times to malformed ciphertexts in RSA-PSK ClientKeyExchange differ from response times of ciphertexts with correct PKCS#1 v1.5 padding.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libgnutls30:3.7.9-2": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", - "full_path": "libgnutls30:3.7.9-2" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-537103", - "cves": [ - { - "cve": "CVE-2023-5981", - "cvss_v3_score": "5.9", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N" - } - ], - "references": [ - "https://gnutls.org/security-new.html#GNUTLS-SA-2023-10-23", - "https://access.redhat.com/errata/RHSA-2024:0451", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNXKVR5YNUEBNHAHM5GSYKBZX4W2HMN2/", - "http://www.openwall.com/lists/oss-security/2024/01/19/3", - "https://access.redhat.com/errata/RHSA-2024:0533", - "https://bugzilla.redhat.com/show_bug.cgi?id=2248445", - "https://access.redhat.com/errata/RHSA-2024:0319", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/7ZEIOLORQ7N6WRPFXZSYDL2MC4LP7VFV/", - "https://access.redhat.com/errata/RHSA-2024:1383", - "https://access.redhat.com/errata/RHSA-2024:0399", - "https://security-tracker.debian.org/tracker/CVE-2023-5981", - "https://access.redhat.com/security/cve/CVE-2023-5981", - "https://access.redhat.com/errata/RHSA-2024:0155" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-537103\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "A flaw was found in shadow-utils. When asking for a new password, shadow-utils asks the password twice. If the password fails on the second attempt, shadow-utils fails in cleaning the buffer used to store the first entry. This may allow an attacker with enough access to retrieve the password from the memory.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1", - "full_path": "login:1:4.13+dfsg1-1+b1" - } - ] - ] - }, - "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1", - "full_path": "passwd:1:4.13+dfsg1-1+b1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-529509", - "cves": [ - { - "cve": "CVE-2023-4641", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N" - } - ], - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-4641", - "https://access.redhat.com/errata/RHSA-2024:2577", - "https://access.redhat.com/security/cve/CVE-2023-4641", - "https://access.redhat.com/errata/RHSA-2023:6632", - "https://bugzilla.redhat.com/show_bug.cgi?id=2215945", - "https://access.redhat.com/errata/RHSA-2024:0417", - "https://access.redhat.com/errata/RHSA-2023:7112" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-529509\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Libde265 v1.0.14 was discovered to contain a global buffer overflow vulnerability in the read_coding_unit function at slice.cc.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] + "xray_version": "3.104.8", + "jas_entitled": true, + "command_type": "docker_image", + "targets": [ + { + "target": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210535-1985298017/image.tar", + "name": "platform.jfrog.io/swamp-docker/swamp:latest", + "technology": "oci", + "sca_scans": { + "xray_scan": [ + { + "scan_id": "27da9106-88ea-416b-799b-bc7d15783473", + "vulnerabilities": [ + { + "cves": [ + { + "cve": "CVE-2024-6119" + } + ], + "summary": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libssl3:3.0.13-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://platform.jfrog.io/swamp-docker/swamp:latest" + }, + { + "component_id": "generic://sha256:f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595/sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "full_path": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.13-1~deb12u1", + "full_path": "libssl3:3.0.13-1~deb12u1" + } ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-540358", - "cves": [ - { - "cve": "CVE-2023-49468", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://lists.debian.org/debian-lts-announce/2023/12/msg00022.html", - "https://security-tracker.debian.org/tracker/CVE-2023-49468", - "https://github.com/strukturag/libde265/issues/432" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540358\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "A buffer overflow (in a global variable) in libde265 causes memory corruption leading to DoS and possibly code execution, when parsing attacker-supplied H.265 data.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "The provided PoC demonstrates a crash." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker must be able to provide remote input that will be parsed by H.265, for example - `./dec265 attacker_input`.", - "is_positive": true - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "The impact of this vulnerability depends on the implementation of the vulnerable library. Substantial research has to be conducted to determine the exact impact this vulnerability could have. Code execution is not always achievable through a buffer overflow in a global variable.", - "is_positive": true - } ] - } - }, - { - "summary": "A vulnerability was found in GnuTLS. The response times to malformed ciphertexts in RSA-PSK ClientKeyExchange differ from the response times of ciphertexts with correct PKCS#1 v1.5 padding. This issue may allow a remote attacker to perform a timing side-channel attack in the RSA-PSK key exchange, potentially leading to the leakage of sensitive data. CVE-2024-0553 is designated as an incomplete resolution for CVE-2023-5981.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libgnutls30:3.7.9-2": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", - "full_path": "libgnutls30:3.7.9-2" - } - ] - ] - } }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-588549", - "cves": [ - { - "cve": "CVE-2024-0553", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N" - } - ], - "references": [ - "https://access.redhat.com/errata/RHSA-2024:2094", - "https://access.redhat.com/errata/RHSA-2024:0627", - "https://gitlab.com/gnutls/gnutls/-/issues/1522", - "https://access.redhat.com/errata/RHSA-2024:1383", - "https://access.redhat.com/errata/RHSA-2024:0796", - "http://www.openwall.com/lists/oss-security/2024/01/19/3", - "https://security.netapp.com/advisory/ntap-20240202-0011/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNXKVR5YNUEBNHAHM5GSYKBZX4W2HMN2/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/7ZEIOLORQ7N6WRPFXZSYDL2MC4LP7VFV/", - "https://lists.gnupg.org/pipermail/gnutls-help/2024-January/004841.html", - "https://access.redhat.com/errata/RHSA-2024:1108", - "https://lists.debian.org/debian-lts-announce/2024/02/msg00010.html", - "https://access.redhat.com/security/cve/CVE-2024-0553", - "https://access.redhat.com/errata/RHSA-2024:0533", - "https://access.redhat.com/errata/RHSA-2024:1082", - "https://bugzilla.redhat.com/show_bug.cgi?id=2258412", - "https://security-tracker.debian.org/tracker/CVE-2024-0553" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-588549\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "A design problem in GnuTLS may lead to RSA key brute force when attackers can cause many decryption operations.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue can be exploited by attackers over the network", - "description": "This vulnerability does not rely on timing to exploit, but rather on the server informing the client that decryption failed, hence it can be exploited remotely, completely disregarding latency issues." - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The given CVSS score does not take the context required to exploit the vulnerability into account.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "This CVE is only exploitable when all of the following conditions are met:\n\n1. The server must use `RSA` for key exchange.\n2. The server encrypts/decrypts `RSA` with `PKCS#1 v1.5` padding.\n3. The server informs the client when decryption fails.\n4. An attacker is on the same subnet, hijacks a session between the client and the server and manipulates the client data.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "A successful attack would compromise the server's private RSA key, allowing the attacker to decrypt any sniffed TLS traffic sent to or from the server from any host." - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Although Bleichenbacher's Attack is well documented today, a high technical understanding of cryptography is required to exploit it.", - "is_positive": true - } + "deb://debian:bookworm:openssl:3.0.13-1~deb12u1": { + "fixed_versions": [ + "[3.0.14-1~deb12u2]" ], - "remediation": "##### Development mitigations\n\n- When choosing a key exchange for your server, avoid using `RSA` and instead opt for the `Diffie-Hellman` key exchange, which provides forward secrecy.\nThis can be done by generating an ECDH key using OpenSSL:\n`openssl ecparam -name prime256v1 -genkey -noout -out mykey-prime256v1.pem`\nAnd giving the filepath of the keyfile to the `gnutls_certificate_set_x509_key_file` function - \n```c\ngnutls_certificate_set_x509_key_file(res, certfile, \"mykey-prime256v1.pem\", GNUTLS_X509_FMT_PEM);\n```\n\n- When using `RSA` for key exchange, use the `OAEP` padding scheme instead of `PKCS#1 v1.5`.\n\n- When using `RSA` and `PKCS#1` for key exchange, avoid informing the client of decryption failure." - } - }, - { - "summary": "libcurl's ASN1 parser code has the `GTime2str()` function, used for parsing an\nASN.1 Generalized Time field. If given an syntactically incorrect field, the\nparser might end up using -1 for the length of the *time fraction*, leading to\na `strlen()` getting performed on a pointer to a heap buffer area that is not\n(purposely) null terminated.\n\nThis flaw most likely leads to a crash, but can also lead to heap contents\ngetting returned to the application when\n[CURLINFO_CERTINFO](https://curl.se/libcurl/c/CURLINFO_CERTINFO.html) is used.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:curl:7.88.1-10+deb12u4": { - "fixed_versions": [ - "[7.88.1-10+deb12u7]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:curl:7.88.1-10+deb12u4", - "full_path": "curl:7.88.1-10+deb12u4" - } - ] - ] - }, - "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4", - "full_path": "libcurl4:7.88.1-10+deb12u4" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-617171", - "cves": [ - { - "cve": "CVE-2024-7264", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://hackerone.com/reports/2629968", - "https://security-tracker.debian.org/tracker/CVE-2024-7264", - "https://curl.se/docs/CVE-2024-7264.json", - "http://www.openwall.com/lists/oss-security/2024/07/31/1", - "https://curl.se/docs/CVE-2024-7264.html" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-617171\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Increasing the resolution of video frames, while performing a multi-threaded encode, can result in a heap overflow in av1_loop_restoration_dealloc().", - "severity": "Critical", - "type": "security", - "components": { - "deb://debian:bookworm:libaom3:3.6.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libaom3:3.6.0-1", - "full_path": "libaom3:3.6.0-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-585747", - "cves": [ - { - "cve": "CVE-2023-6879", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://aomedia.googlesource.com/aom/+/refs/tags/v3.7.1", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D6C2HN4T2S6GYNTAUXLH45LQZHK7QPHP/", - "https://crbug.com/aomedia/3491", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/AYONA2XSNFMXLAW4IHLFI5UVV3QRNG5K/", - "https://security-tracker.debian.org/tracker/CVE-2023-6879" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-585747\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "Heap buffer overread in the av1 module of the aom library can lead to denial of service when resizing frames under special conditions.", - "full_description": "AOM (Alliance for Open Media) is an open-source, royalty-free video codec library implemented in C, developed by the Alliance for Open Media, a consortium of technology companies and research institutions. The AOM library supports the AV1, VP9, and Thor video formats, providing high-quality video compression and is used for a variety of applications, including video streaming, video conferencing, and video editing.\nThe AV1 codec, developed by the Alliance for Open Media, is a state-of-the-art video compression technology that achieves exceptional efficiency while preserving high visual quality. The AOM library provides a comprehensive toolkit for working with AV1-encoded video streams, offering encoding, decoding, and manipulation capabilities.\n\nA vulnerability was found when using the `aom_codec_destroy()` function to clean up memory after resizing AV1 frames, specifically when:\n\n- Using AV1 codec (`aom_codec_av1_cx()`)\n- Utilizing multiple threads\n```\naom_codec_enc_cfg_t cfg;\naom_codec_enc_config_default(iface, \u0026cfg, AOM_USAGE_GOOD_QUALITY));\ncfg.g_threads = 4;\n```\n\nUnder these conditions, a Denial of Service (DoS) vulnerability emerges, manifesting as a heap buffer overread during object destruction.", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "A public example of vulnerable AOM code exists, which shows how a DoS might be triggered." - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "Under normal circumstances, the attacker cannot supply input which will trigger this vulnerability (either the vulnerable code exists or does not exist).", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The vulnerability triggers under the following conditions -\n- use of the AV1 codec (`aom_codec_av1_cx()`)\n- use of more than 1 thread:\n```\naom_codec_enc_cfg_t cfg;\naom_codec_enc_config_default(iface, \u0026cfg, AOM_USAGE_GOOD_QUALITY));\ncfg.g_threads = 4;\n```\n- cleaning the memory at the end of the encoding process (`aom_codec_destroy()`)", - "is_positive": true - } - ] - } - }, - { - "summary": "An issue was discovered in libxml2 before 2.11.7 and 2.12.x before 2.12.5. When using the XML Reader interface with DTD validation and XInclude expansion enabled, processing crafted XML documents can lead to an xmlValidatePopElement use-after-free.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1": { - "fixed_versions": [ - "[2.12.7+dfsg-1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1", - "full_path": "libxml2:2.9.14+dfsg-1.3~deb12u1" - } - ] + "impact_paths": [ + [ + { + "component_id": "docker://platform.jfrog.io/swamp-docker/swamp:latest" + }, + { + "component_id": "generic://sha256:f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595/sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "full_path": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.13-1~deb12u1", + "full_path": "openssl:3.0.13-1~deb12u1" + } ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-589897", - "cves": [ - { - "cve": "CVE-2024-25062", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-25062", - "https://gitlab.gnome.org/GNOME/libxml2/-/tags", - "https://gitlab.gnome.org/GNOME/libxml2/-/issues/604" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589897\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "A use-after-free in libxml2 may lead to denial of service when parsing a crafted XML document with specific parser arguments.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "Exploiting this issue using static XML requires that the `XML_PARSE_XINCLUDE` (--xinclude) and the `XML_PARSE_VALIDATE` (--valid) flags are used.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Exploiting the vulnerability may lead to denial of service." - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS score does not take into account the contextual prerequisites required to exploit the vulnerability.", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "A PoC that triggers the use-after-free is available in the Git issue." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker must be able to control an XML file that is getting parsed by `xmlTextReaderRead()` with the xinclude and DTD validation options enabled. This can be achieved by passing both the `XML_PARSE_XINCLUDE` (--xinclude) and `XML_PARSE_VALIDATE` (--valid) flags when parsing the document.", - "is_positive": true - } ] } }, - { - "summary": "A vulnerability, which was classified as critical, was found in Linux Kernel. This affects the function __mtk_ppe_check_skb of the file drivers/net/ethernet/mediatek/mtk_ppe.c of the component Ethernet Handler. The manipulation leads to use after free. It is recommended to apply a patch to fix this issue. The associated identifier of this vulnerability is VDB-211935.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-414609", - "cves": [ - { - "cve": "CVE-2022-3636", - "cvss_v3_score": "7.8", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://git.kernel.org/pub/scm/linux/kernel/git/pabeni/net-next.git/commit/?id=17a5f6a78dc7b8db385de346092d7d9f9dc24df6", - "https://vuldb.com/?id.211935", - "https://www.debian.org/security/2023/dsa-5333", - "https://security-tracker.debian.org/tracker/CVE-2022-3636" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-414609\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "An out-of-memory flaw was found in libtiff. Passing a crafted tiff file to TIFFOpen() API may allow a remote attacker to cause a denial of service via a craft input with size smaller than 379 KB.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-539830", - "cves": [ - { - "cve": "CVE-2023-6277", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://gitlab.com/libtiff/libtiff/-/issues/614", - "https://support.apple.com/kb/HT214123", - "https://support.apple.com/kb/HT214118", - "https://support.apple.com/kb/HT214122", - "https://support.apple.com/kb/HT214120", - "http://seclists.org/fulldisclosure/2024/Jul/21", - "http://seclists.org/fulldisclosure/2024/Jul/19", - "https://support.apple.com/kb/HT214117", - "http://seclists.org/fulldisclosure/2024/Jul/20", - "http://seclists.org/fulldisclosure/2024/Jul/23", - "https://support.apple.com/kb/HT214116", - "http://seclists.org/fulldisclosure/2024/Jul/16", - "https://support.apple.com/kb/HT214119", - "https://support.apple.com/kb/HT214124", - "http://seclists.org/fulldisclosure/2024/Jul/17", - "http://seclists.org/fulldisclosure/2024/Jul/22", - "http://seclists.org/fulldisclosure/2024/Jul/18", - "https://security.netapp.com/advisory/ntap-20240119-0002/", - "https://access.redhat.com/security/cve/CVE-2023-6277", - "https://bugzilla.redhat.com/show_bug.cgi?id=2251311", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/Y7ZGN2MZXJ6E57W3L4YBM3ZPAU3T7T5C/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/WJIN6DTSL3VODZUGWEUXLEL5DR53EZMV/", - "https://security-tracker.debian.org/tracker/CVE-2023-6277", - "https://gitlab.com/libtiff/libtiff/-/merge_requests/545" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-539830\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "In MIT Kerberos 5 (aka krb5) before 1.21.3, an attacker can modify the plaintext Extra Count field of a confidential GSS krb5 wrap token, causing the unwrapped token to appear truncated to the application.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", - "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", - "full_path": "libk5crypto3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", - "full_path": "libkrb5-3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", - "full_path": "libkrb5support0:1.20.1-2+deb12u1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-607812", - "cves": [ - { - "cve": "CVE-2024-37370", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N" - } - ], - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-37370", - "https://web.mit.edu/kerberos/www/advisories/", - "https://github.com/krb5/krb5/commit/55fbf435edbe2e92dd8101669b1ce7144bc96fef" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-607812\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Certain DNSSEC aspects of the DNS protocol (in RFC 4033, 4034, 4035, 6840, and related RFCs) allow remote attackers to cause a denial of service (CPU consumption) via one or more DNSSEC responses, aka the \"KeyTrap\" issue. One of the concerns is that, when there is a zone with many DNSKEY and RRSIG records, the protocol specification implies that an algorithm must evaluate all combinations of DNSKEY and RRSIG records.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", - "full_path": "libsystemd0:252.17-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", - "full_path": "libudev1:252.17-1~deb12u1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-590537", - "cves": [ - { - "cve": "CVE-2023-50387", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://security.netapp.com/advisory/ntap-20240307-0007/", - "http://www.openwall.com/lists/oss-security/2024/02/16/2", - "https://www.theregister.com/2024/02/13/dnssec_vulnerability_internet/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/6FV5O347JTX7P5OZA6NGO4MKTXRXMKOZ/", - "https://news.ycombinator.com/item?id=39367411", - "https://www.athene-center.de/aktuelles/key-trap", - "https://nlnetlabs.nl/news/2024/Feb/13/unbound-1.19.1-released/", - "https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2024q1/017430.html", - "https://www.isc.org/blogs/2024-bind-security-release/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/ZDZFMEKQTZ4L7RY46FCENWFB5MDT263R/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/RGS7JN6FZXUSTC2XKQHH27574XOULYYJ/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/TEXGOYGW7DBS3N2QSSQONZ4ENIRQEAPG/", - "https://bugzilla.suse.com/show_bug.cgi?id=1219823", - "https://lists.debian.org/debian-lts-announce/2024/05/msg00011.html", - "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-50387", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/HVRDSJVZKMCXKKPP6PNR62T7RWZ3YSDZ/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/PNNHZSZPG2E7NBMBNYPGHCFI4V4XRWNQ/", - "https://gitlab.nic.cz/knot/knot-resolver/-/releases/v5.7.1", - "https://www.athene-center.de/fileadmin/content/PDF/Technical_Report_KeyTrap.pdf", - "https://www.securityweek.com/keytrap-dns-attack-could-disable-large-parts-of-internet-researchers/", - "https://lists.debian.org/debian-lts-announce/2024/02/msg00006.html", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/SVYA42BLXUCIDLD35YIJPJSHDIADNYMP/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/BUIP7T7Z4T3UHLXFWG6XIVDP4GYPD3AI/", - "https://security-tracker.debian.org/tracker/CVE-2023-50387", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/IGSLGKUAQTW5JPPZCMF5YPEYALLRUZZ6/", - "https://kb.isc.org/docs/cve-2023-50387", - "https://docs.powerdns.com/recursor/security-advisories/powerdns-advisory-2024-01.html", - "https://news.ycombinator.com/item?id=39372384", - "http://www.openwall.com/lists/oss-security/2024/02/16/3", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/UQESRWMJCF4JEYJEAKLRM6CT55GLJAB7/", - "https://access.redhat.com/security/cve/CVE-2023-50387" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-590537\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "Unbounded resource consumption in the DNSSEC extension of the DNS protocol may lead to denial of service when resolving a malicious domain.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are either extremely common or nonexistent (always exploitable)", - "description": "To exploit the vulnerability, an attacker needs to make the victim resolver validate his malicious domain.\nNote - This flaw is derived from the DNSSEC standard, thus every implementation of DNSSEC that follows the standard is vulnerable." - }, - { - "name": "The issue can be exploited by attackers over the network", - "description": "The attacker needs to send a DNS query to the target resolver, requesting his malicious domain. The attack occurs when the resolver tries to validate the response from the DNS server." - }, - { - "name": "The issue has an exploit published", - "description": "A PoC was published, demonstrating denial of service." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Exploitation of the vulnerability causes high resource consumption, which leads to denial of service." - }, - { - "name": "The issue has a detailed technical explanation published, that can aid in exploit development", - "description": "A technically detailed writeup of this vulnerability (under the name \"keytrap\") was published by the research team, ATHENE-RESEARC." - } - ], - "remediation": "##### Deployment mitigations\n\nSince the vulnerability affects many different DNS resolvers, remediation is on a case-by-case basis." - } - }, - { - "summary": "libtiff 4.5.0 is vulnerable to Buffer Overflow in uv_encode() when libtiff reads a corrupted little-endian TIFF file and specifies the output to be big-endian.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-522650", - "cves": [ - { - "cve": "CVE-2023-26966", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", - "https://security-tracker.debian.org/tracker/CVE-2023-26966", - "https://gitlab.com/libtiff/libtiff/-/issues/530", - "https://gitlab.com/libtiff/libtiff/-/merge_requests/473" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-522650\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "VideoLAN dav1d before 1.2.0 has a thread_task.c race condition that can lead to an application crash, related to dav1d_decode_frame_exit.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libdav1d6:1.0.0-2": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libdav1d6:1.0.0-2", - "full_path": "libdav1d6:1.0.0-2" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-519404", - "cves": [ - { - "cve": "CVE-2023-32570", - "cvss_v3_score": "5.9", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/3WGSO7UMOF4MVLQ5H6KIV7OG6ONS377B/", - "https://security-tracker.debian.org/tracker/CVE-2023-32570", - "https://code.videolan.org/videolan/dav1d/-/tags/1.2.0", - "https://code.videolan.org/videolan/dav1d/-/commit/cf617fdae0b9bfabd27282854c8e81450d955efa", - "https://security.gentoo.org/glsa/202310-05", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LXZ6CUNJFDJLCFOZHY2TIGMCAEITLCRP/" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-519404\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the function UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libheif1:1.15.1-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", - "full_path": "libheif1:1.15.1-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-540356", - "cves": [ - { - "cve": "CVE-2023-49464", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://github.com/strukturag/libheif/issues/1044", - "https://security-tracker.debian.org/tracker/CVE-2023-49464" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540356\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "A use-after-free in libheif leads to denial of service and possibly remote code execution.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS score given to this CVE does not take into account the unlikely prerequisites for applicability of this vulnerability and the context required to exploit it.", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "The fixing PR contains a denial of service PoC" - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "An attacker needs to find a remote input that propagates into the function `UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci`.", - "is_positive": true - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "For this vulnerability to be applicable, `libheif1` needs to be compiled with the flag `-DWITH_UNCOMPRESSED_CODEC=ON`.\n\nWe found that this setting is enabled only in some package managers by default, but not all of them. In vanilla compilations, this flag is disabled by default.", - "is_positive": true - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Exploitation requires triggering a use-after-free beyond the scope of a single function. The use-after-free has not been proven to be able to cause code execution.", - "is_positive": true - } - ] - } - }, - { - "summary": "An issue was discovered in libexpat before 2.6.3. dtdCopy in xmlparse.c can have an integer overflow for nDefaultAtts on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", - "severity": "Critical", - "type": "security", - "components": { - "deb://debian:bookworm:libexpat1:2.5.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", - "full_path": "libexpat1:2.5.0-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-632611", - "cves": [ - { - "cve": "CVE-2024-45491", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-45491", - "https://github.com/libexpat/libexpat/pull/891", - "https://github.com/libexpat/libexpat/issues/888" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-632611\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "This flaw allows a malicious HTTP server to set \"super cookies\" in curl that\nare then passed back to more origins than what is otherwise allowed or\npossible. This allows a site to set cookies that then would get sent to\ndifferent and unrelated sites and domains.\n\nIt could do this by exploiting a mixed case flaw in curl's function that\nverifies a given cookie domain against the Public Suffix List (PSL). For\nexample a cookie could be set with `domain=co.UK` when the URL used a lower\ncase hostname `curl.co.uk`, even though `co.uk` is listed as a PSL domain.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:curl:7.88.1-10+deb12u4": { - "fixed_versions": [ - "[7.88.1-10+deb12u5]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:curl:7.88.1-10+deb12u4", - "full_path": "curl:7.88.1-10+deb12u4" - } - ] - ] - }, - "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4", - "full_path": "libcurl4:7.88.1-10+deb12u4" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-540279", - "cves": [ - { - "cve": "CVE-2023-46218", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N" - } - ], - "references": [ - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/3ZX3VW67N4ACRAPMV2QS2LVYGD7H2MVE/", - "https://security-tracker.debian.org/tracker/CVE-2023-46218", - "https://lists.debian.org/debian-lts-announce/2023/12/msg00015.html", - "https://curl.se/docs/CVE-2023-46218.html", - "https://hackerone.com/reports/2212193", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UOGXU25FMMT2X6UUITQ7EZZYMJ42YWWD/", - "https://security.netapp.com/advisory/ntap-20240125-0007/", - "https://www.debian.org/security/2023/dsa-5587" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540279\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "NGINX Open Source and NGINX Plus have a vulnerability in the ngx_http_mp4_module, which might allow an attacker to over-read NGINX worker memory resulting in its termination, using a specially crafted mp4 file. The issue only affects NGINX if it is built with the ngx_http_mp4_module and the mp4 directive is used in the configuration file. Additionally, the attack is possible only if an attacker can trigger the processing of a specially crafted mp4 file with the ngx_http_mp4_module.  Note: Software versions which have reached End of Technical Support (EoTS) are not evaluated.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:nginx:1.25.2-1~bookworm": { - "fixed_versions": [ - "[1.26.0-2]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:nginx:1.25.2-1~bookworm", - "full_path": "nginx:1.25.2-1~bookworm" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-619023", - "cves": [ - { - "cve": "CVE-2024-7347", - "cvss_v3_score": "4.7", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-7347", - "https://my.f5.com/manage/s/article/K000140529" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-619023\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Issue summary: A bug has been identified in the processing of key and\ninitialisation vector (IV) lengths. This can lead to potential truncation\nor overruns during the initialisation of some symmetric ciphers.\n\nImpact summary: A truncation in the IV can result in non-uniqueness,\nwhich could result in loss of confidentiality for some cipher modes.\n\nWhen calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or\nEVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after\nthe key and IV have been established. Any alterations to the key length,\nvia the \"keylen\" parameter or the IV length, via the \"ivlen\" parameter,\nwithin the OSSL_PARAM array will not take effect as intended, potentially\ncausing truncation or overreading of these values. The following ciphers\nand cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.\n\nFor the CCM, GCM and OCB cipher modes, truncation of the IV can result in\nloss of confidentiality. For example, when following NIST's SP 800-38D\nsection 8.2.1 guidance for constructing a deterministic IV for AES in\nGCM mode, truncation of the counter portion could lead to IV reuse.\n\nBoth truncations and overruns of the key and overruns of the IV will\nproduce incorrect results and could, in some cases, trigger a memory\nexception. However, these issues are not currently assessed as security\ncritical.\n\nChanging the key and/or IV lengths is not considered to be a common operation\nand the vulnerable API was recently introduced. Furthermore it is likely that\napplication developers will have spotted this problem during testing since\ndecryption would fail unless both peers in the communication were similarly\nvulnerable. For these reasons we expect the probability of an application being\nvulnerable to this to be quite low. However if an application is vulnerable then\nthis issue is considered very serious. For these reasons we have assessed this\nissue as Moderate severity overall.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\n\nThe OpenSSL 3.0 and 3.1 FIPS providers are...", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "fixed_versions": [ - "[3.0.11-1~deb12u2]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-534361", - "cves": [ - { - "cve": "CVE-2023-5363", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N" - } - ], - "references": [ - "https://security.netapp.com/advisory/ntap-20231027-0010/", - "https://www.openssl.org/news/secadv/20231024.txt", - "https://security-tracker.debian.org/tracker/CVE-2023-5363", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=5f69f5c65e483928c4b28ed16af6e5742929f1ee", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=0df40630850fb2740e6be6890bb905d3fc623b2d", - "https://www.debian.org/security/2023/dsa-5532", - "https://security.netapp.com/advisory/ntap-20240201-0004/", - "http://www.openwall.com/lists/oss-security/2023/10/24/1", - "https://security.netapp.com/advisory/ntap-20240201-0003/" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-534361\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "A design problem in OpenSSL 3.x may lead to data leakage when processing cipher parameters.", - "full_description": "OpenSSL is an open-source cryptographic library and toolset that provides a wide range of protocol supported and functions for secure communication, data encryption, digital certificates, and other cryptographic operations, widely used in various software applications and systems.\nIn cryptography, a block cipher is a symmetric key algorithm that encrypts fixed-size blocks of data, typically 64 or 128 bits, transforming each block into a corresponding ciphertext block using a key-specific permutation.\n\nA major problem with block ciphers, is that equal plaintext blocks get transformed to equal ciphertexts. This can be used for a known-plaintext attack, where an adversary possesses both the plaintext and its corresponding encrypted form, aiming to deduce the encryption key or gain insights into the encryption algorithm.\n\nTo counter this, we use an Initialization vector (IV), which is a random or unique input to a cryptographic algorithm used to alter the first block of the cipher, ensuring equal plaintext blocks won’t be transformed to equal ciphertexts.\n\nA vulnerability was found in OpenSSL 3.x, in certain situations, parameters such as key length or IV length, will be processed after the key and IV have been established, hence they will not take effect as intended, potentially causing truncation or overreading of these values, impacting the confidentiality of the encryption.\n\nWhen calling the functions `EVP_CipherInit_ex2`, `EVP_EncryptInit_ex2, or `EVP_DecryptInit_ex2` with an `OSSL_PARAM` array, changes to the `keylen` or `ivlen` parameters will only be processed after the IV and the key have been established.\n\nNote this impacts the following ciphers: RC2, RC4, RC5, and the following cipher modes: CCM, GCM, OCB.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The vulnerability is only applicable if the vulnerable functions `EVP_CipherInit_ex2`, `EVP_EncryptInit_ex2, or `EVP_DecryptInit_ex2` is called directly or indirectly with an `OSSL_PARAM` array that alters the `ivlen` and `keylen` parameters. Moreover, it only impacts the following ciphers: RC2, RC4, RC5, and the following cipher modes: CCM, GCM, OCB.", - "is_positive": true - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "Changing the key or IV lengths is not considered a popular operation. Furthermore, the API only affects OpenSSL 3.x and it is likely the app developers have discovered the problem during testing, as it would have caused the decryption to fail.", - "is_positive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The given CVSS score does not take into account the unlikely prerequisites and the context required to exploit this CVE.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "In the case that this vulnerability is exploited successfully, an attacker can read sensitive data as plaintext, breaking the encryption." - } - ] - } - }, - { - "summary": "The Key Distribution Center (KDC) in MIT Kerberos 5 (aka krb5) 1.9 allows remote attackers to cause a denial of service (NULL pointer dereference and daemon crash) via a malformed request packet that does not trigger a response packet.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", - "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", - "full_path": "libk5crypto3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", - "full_path": "libkrb5-3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", - "full_path": "libkrb5support0:1.20.1-2+deb12u1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-515010", - "cves": [ - { - "cve": "CVE-2011-0283", - "cvss_v2_score": "5.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P" - } - ], - "references": [ - "http://web.mit.edu/kerberos/advisories/MITKRB5-SA-2011-002.txt", - "http://www.securityfocus.com/bid/46272", - "http://securityreason.com/securityalert/8073", - "http://www.vupen.com/english/advisories/2011/0330", - "http://secunia.com/advisories/43260", - "http://www.securitytracker.com/id?1025037", - "http://www.securityfocus.com/archive/1/516299/100/0/threaded", - "https://security-tracker.debian.org/tracker/CVE-2011-0283" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-515010\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Libde265 v1.0.11 was discovered to contain a heap buffer overflow via the function derive_collocated_motion_vectors at motion.cc.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-427848", - "cves": [ - { - "cve": "CVE-2023-27103", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-27103", - "https://github.com/strukturag/libde265/issues/394", - "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-427848\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "A vulnerability was found in GnuTLS, where a cockpit (which uses gnuTLS) rejects a certificate chain with distributed trust. This issue occurs when validating a certificate chain with cockpit-certificate-ensure. This flaw allows an unauthenticated, remote client or attacker to initiate a denial of service attack.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libgnutls30:3.7.9-2": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", - "full_path": "libgnutls30:3.7.9-2" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-588550", - "cves": [ - { - "cve": "CVE-2024-0567", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://access.redhat.com/errata/RHSA-2024:2094", - "https://access.redhat.com/security/cve/CVE-2024-0567", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/7ZEIOLORQ7N6WRPFXZSYDL2MC4LP7VFV/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNXKVR5YNUEBNHAHM5GSYKBZX4W2HMN2/", - "https://bugzilla.redhat.com/show_bug.cgi?id=2258544", - "http://www.openwall.com/lists/oss-security/2024/01/19/3", - "https://security.netapp.com/advisory/ntap-20240202-0011/", - "https://access.redhat.com/errata/RHSA-2024:1383", - "https://lists.gnupg.org/pipermail/gnutls-help/2024-January/004841.html", - "https://access.redhat.com/errata/RHSA-2024:1082", - "https://security-tracker.debian.org/tracker/CVE-2024-0567", - "https://gitlab.com/gnutls/gnutls/-/issues/1521", - "https://access.redhat.com/errata/RHSA-2024:0533" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-588550\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "A design problem in GnuTLS may lead to denial of service when parsing a crafted certificate chain.", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The given CVSS score does not take into account the prerequisites and context required to exploit the vulnerability.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The vulnerability is only exploitable if a GnuTLS client or server calls any of the following functions with externally-supplied input -\n\n- `gnutls_pcert_import_x509_list`\n\n- `gnutls_certificate_set_x509_key`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_mem`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_file`\n\n- `gnutls_privkey_import_url`\n\n- `gnutls_privkey_import_pkcs11_url`\n\n- `gnutls_read_key_file`\n\n- `gnutls_certificate_set_rawpk_key_file`\n\n- `gnutls_certificate_set_x509_key_file2`\n\n- `gnutls_certificate_set_x509_key_file`\n\n- `gnutls_pcert_list_import_x509_file`\n\n- `gnutls_certificate_set_x509_key_mem2`\n\n- `gnutls_certificate_set_x509_key_mem`\n\n- `gnutls_x509_crt_list_import`\n\n- `gnutls_pcert_list_import_x509_raw`\n\n- `gnutls_session_channel_binding`\n\n- `gnutls_x509_crt_list_import2`\n\n- `gnutls_x509_trust_list_add_trust_mem`\n\n- `gnutls_x509_trust_list_add_system_trust`\n\n- `gnutls_certificate_set_x509_system_trust`\n\n- `gnutls_certificate_set_x509_crl_mem`\n\n- `gnutls_certificate_set_x509_trust_mem`\n\n- `gnutls_x509_trust_list_add_trust_file`\n\n- `gnutls_certificate_set_x509_crl_file`\n\n- `gnutls_certificate_set_x509_trust_file`\n\n- `gnutls_x509_trust_list_add_trust_dir`\n\n- `gnutls_certificate_set_x509_trust_dir`\n\n- `gnutls_x509_trust_list_remove_trust_mem`\n\n- `gnutls_x509_trust_list_remove_trust_file`\n\n- `gnutls_x509_trust_list_verify_crt2`\n\n- `gnutls_x509_cert_verify_peers`\n\n- `gnutls_certificate_verify_peers`\n\n- `gnutls_certificate_verify_peers2`\n\n- `gnutls_certificate_verify_peers3`\n\n- `gnutls_pkcs7_verify`\n\n- `gnutls_ocsp_resp_verify`\n\n- `gnutls_x509_trust_list_verify_crt`", - "is_positive": true - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "is_positive": true - } - ] - } - }, - { - "summary": "When saving HSTS data to an excessively long file name, curl could end up\nremoving all contents, making subsequent requests using that file unaware of\nthe HSTS status they should otherwise use.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:curl:7.88.1-10+deb12u4": { - "fixed_versions": [ - "[7.88.1-10+deb12u5]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:curl:7.88.1-10+deb12u4", - "full_path": "curl:7.88.1-10+deb12u4" - } - ] - ] - }, - "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4", - "full_path": "libcurl4:7.88.1-10+deb12u4" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-540277", - "cves": [ - { - "cve": "CVE-2023-46219", - "cvss_v3_score": "5.3", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N" - } - ], - "references": [ - "https://www.debian.org/security/2023/dsa-5587", - "https://security.netapp.com/advisory/ntap-20240119-0007/", - "https://hackerone.com/reports/2236133", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UOGXU25FMMT2X6UUITQ7EZZYMJ42YWWD/", - "https://curl.se/docs/CVE-2023-46219.html", - "https://security-tracker.debian.org/tracker/CVE-2023-46219" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540277\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "libtiff 4.5.0 is vulnerable to Buffer Overflow via /libtiff/tools/tiffcrop.c:8499. Incorrect updating of buffer size after rotateImage() in tiffcrop cause heap-buffer-overflow and SEGV.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-523034", - "cves": [ - { - "cve": "CVE-2023-25433", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://gitlab.com/libtiff/libtiff/-/merge_requests/467", - "https://security-tracker.debian.org/tracker/CVE-2023-25433", - "https://gitlab.com/libtiff/libtiff/-/issues/520", - "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-523034\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "A null pointer dereference flaw was found in Libtiff via `tif_dirinfo.c`. This issue may allow an attacker to trigger memory allocation failures through certain means, such as restricting the heap space size or injecting faults, causing a segmentation fault. This can cause an application crash, eventually leading to a denial of service.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-617888", - "cves": [ - { - "cve": "CVE-2024-7006", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-7006", - "https://access.redhat.com/security/cve/CVE-2024-7006", - "https://bugzilla.redhat.com/show_bug.cgi?id=2302996", - "https://access.redhat.com/errata/RHSA-2024:6360" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-617888\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "libexpat through 2.5.0 allows a denial of service (resource consumption) because many full reparsings are required in the case of a large token for which multiple buffer fills are needed.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libexpat1:2.5.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", - "full_path": "libexpat1:2.5.0-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-589898", - "cves": [ - { - "cve": "CVE-2023-52425", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "http://www.openwall.com/lists/oss-security/2024/03/20/5", - "https://security.netapp.com/advisory/ntap-20240614-0003/", - "https://github.com/libexpat/libexpat/pull/789", - "https://lists.debian.org/debian-lts-announce/2024/04/msg00006.html", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/PNRIHC7DVVRAIWFRGV23Y6UZXFBXSQDB/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/WNUBSGZFEZOBHJFTAD42SAN4ATW2VEMV/", - "https://security-tracker.debian.org/tracker/CVE-2023-52425" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589898\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "A design problem in libexpat may lead to denial of service when parsing a crafted XML document with large tokens.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "A PoC demonstrating denial-of-service can be found in Expat's tests." - }, - { - "name": "The issue is trivial to exploit and does not require a published writeup or PoC", - "description": "The issue doesn't require any in-depth knowledge to trigger as a proof-of-concept exists in the official fix commit." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Exploitation of the vulnerability leads to high resource consumption which may lead to denial of service." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "Exploitation requires passing user-controlled input to an XML parsing function such as `XML_Parse`.", - "is_positive": true - } - ] - } - }, - { - "summary": "libxml2 through 2.11.5 has a use-after-free that can only occur after a certain memory allocation fails. This occurs in xmlUnlinkNode in tree.c. NOTE: the vendor's position is \"I don't think these issues are critical enough to warrant a CVE ID ... because an attacker typically can't control when memory allocations fail.\"", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1": { - "fixed_versions": [ - "[2.12.7+dfsg-1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1", - "full_path": "libxml2:2.9.14+dfsg-1.3~deb12u1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-533060", - "cves": [ - { - "cve": "CVE-2023-45322", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://gitlab.gnome.org/GNOME/libxml2/-/issues/583", - "http://www.openwall.com/lists/oss-security/2023/10/06/5", - "https://security-tracker.debian.org/tracker/CVE-2023-45322", - "https://gitlab.gnome.org/GNOME/libxml2/-/issues/344" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-533060\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Issue summary: Generating excessively long X9.42 DH keys or checking\nexcessively long X9.42 DH keys or parameters may be very slow.\n\nImpact summary: Applications that use the functions DH_generate_key() to\ngenerate an X9.42 DH key may experience long delays. Likewise, applications\nthat use DH_check_pub_key(), DH_check_pub_key_ex() or EVP_PKEY_public_check()\nto check an X9.42 DH key or X9.42 DH parameters may experience long delays.\nWhere the key or parameters that are being checked have been obtained from\nan untrusted source this may lead to a Denial of Service.\n\nWhile DH_check() performs all the necessary checks (as of CVE-2023-3817),\nDH_check_pub_key() doesn't make any of these checks, and is therefore\nvulnerable for excessively large P and Q parameters.\n\nLikewise, while DH_generate_key() performs a check for an excessively large\nP, it doesn't check for an excessively large Q.\n\nAn application that calls DH_generate_key() or DH_check_pub_key() and\nsupplies a key or parameters obtained from an untrusted source could be\nvulnerable to a Denial of Service attack.\n\nDH_generate_key() and DH_check_pub_key() are also called by a number of\nother OpenSSL functions. An application calling any of those other\nfunctions may similarly be affected. The other functions affected by this\nare DH_check_pub_key_ex(), EVP_PKEY_public_check(), and EVP_PKEY_generate().\n\nAlso vulnerable are the OpenSSL pkey command line application when using the\n\"-pubcheck\" option, as well as the OpenSSL genpkey command line application.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\n\nThe OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "fixed_versions": [ - "[3.0.13-1~deb12u1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-535129", - "cves": [ - { - "cve": "CVE-2023-5678", - "cvss_v3_score": "5.3", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L" - } - ], - "references": [ - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=34efaef6c103d636ab507a0cc34dca4d3aecc055", - "https://security.netapp.com/advisory/ntap-20231130-0010/", - "http://www.openwall.com/lists/oss-security/2024/03/11/1", - "https://security-tracker.debian.org/tracker/CVE-2023-5678", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=710fee740904b6290fef0dd5536fbcedbc38ff0c", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=db925ae2e65d0d925adef429afc37f75bd1c2017", - "https://www.openssl.org/news/secadv/20231106.txt", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=ddeb4b6c6d527e54ce9a99cba785c0f7776e54b6" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-535129\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "MiniZip in zlib through 1.3 has an integer overflow and resultant heap-based buffer overflow in zipOpenNewFileInZip4_64 via a long filename, comment, or extra field. NOTE: MiniZip is not a supported part of the zlib product. NOTE: pyminizip through 0.2.6 is also vulnerable because it bundles an affected zlib version, and exposes the applicable MiniZip code through its compress API.", - "severity": "Critical", - "type": "security", - "components": { - "deb://debian:bookworm:zlib1g:1:1.2.13.dfsg-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:zlib1g:1:1.2.13.dfsg-1", - "full_path": "zlib1g:1:1.2.13.dfsg-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-533715", - "cves": [ - { - "cve": "CVE-2023-45853", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "http://www.openwall.com/lists/oss-security/2024/01/24/10", - "http://www.openwall.com/lists/oss-security/2023/10/20/9", - "https://github.com/madler/zlib/blob/ac8f12c97d1afd9bafa9c710f827d40a407d3266/contrib/README.contrib#L1-L4", - "https://www.winimage.com/zLibDll/minizip.html", - "https://chromium.googlesource.com/chromium/src/+/de29dd6c7151d3cd37cb4cf0036800ddfb1d8b61", - "https://pypi.org/project/pyminizip/#history", - "https://lists.debian.org/debian-lts-announce/2023/11/msg00026.html", - "https://security.gentoo.org/glsa/202401-18", - "https://chromium.googlesource.com/chromium/src/+/d709fb23806858847131027da95ef4c548813356", - "https://github.com/madler/zlib/pull/843", - "https://security.netapp.com/advisory/ntap-20231130-0009/", - "https://security-tracker.debian.org/tracker/CVE-2023-45853" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-533715\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "A heap buffer overflow in zlib may lead to remote code execution when parsing a malicious archive.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "PoC demonstrates a heap overflow that crashes the application. Although not demonstrated, it is likely that an RCE exploit could be developed, since zip-processing may allow many heap-shaping primitives needed for a full RCE exploit." - }, - { - "name": "The issue can be exploited by attackers over the network", - "description": "An attacker could compromise a server that is using the `zlib` library to zip or unzip any files." - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS score does not reflect the context-dependent nature of this vulnerability.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Remote code execution." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "An attacker must find a way to upload a crafted zip archive, that is subsequently processed by the vulnerable `zipOpenNewFileInZip4_64` function.", - "is_positive": true - } - ], - "remediation": "##### Development mitigations\n\nMake sure that files with names larger than 65536 characters are not parsed using `zlib`.\n\nAlso, a fix currently exists in the `develop` branch of `zlib` and can be deployed manually." - } - }, - { - "summary": "NCurse v6.4-20230418 was discovered to contain a segmentation fault via the component _nc_wrap_entry().", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libtinfo6:6.4-4": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libtinfo6:6.4-4", - "full_path": "libtinfo6:6.4-4" - } - ] - ] - }, - "deb://debian:bookworm:ncurses-base:6.4-4": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:ncurses-base:6.4-4", - "full_path": "ncurses-base:6.4-4" - } - ] - ] - }, - "deb://debian:bookworm:ncurses-bin:6.4-4": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:ncurses-bin:6.4-4", - "full_path": "ncurses-bin:6.4-4" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-540521", - "cves": [ - { - "cve": "CVE-2023-50495", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LU4MYMKFEZQ5VSCVLRIZGDQOUW3T44GT/", - "https://lists.gnu.org/archive/html/bug-ncurses/2023-04/msg00020.html", - "https://security.netapp.com/advisory/ntap-20240119-0008/", - "https://security-tracker.debian.org/tracker/CVE-2023-50495", - "https://lists.gnu.org/archive/html/bug-ncurses/2023-04/msg00029.html" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540521\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "A vulnerability was found in libtiff due to multiple potential integer overflows in raw2tiff.c. This flaw allows remote attackers to cause a denial of service or possibly execute an arbitrary code via a crafted tiff image, which triggers a heap-based buffer overflow.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-529113", - "cves": [ - { - "cve": "CVE-2023-41175", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://bugzilla.redhat.com/show_bug.cgi?id=2235264", - "https://access.redhat.com/errata/RHSA-2024:2289", - "https://security-tracker.debian.org/tracker/CVE-2023-41175", - "https://access.redhat.com/security/cve/CVE-2023-41175" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-529113\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "An integer overflow in libtiff's raw2tiff may lead to remote code execution when parsing crafted images.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "For an attacker to exploit this vulnerability, `raw2tiff` has to be invoked with the `-l`, `-b` and `-w` flags. In addition to this, the attacker has to be able to supply a crafted TIFF file as input.", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "PoC was published along with the git issue." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "The vulnerability leads to denial of service and possibly remote code execution." - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Although integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", - "is_positive": true - } - ] - } - }, - { - "summary": "A vulnerability was found in openldap. This security flaw causes a null pointer dereference in ber_memalloc_x() function.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5", - "full_path": "libldap-2.5-0:2.5.13+dfsg-5" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-520865", - "cves": [ - { - "cve": "CVE-2023-2953", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "http://seclists.org/fulldisclosure/2023/Jul/48", - "https://support.apple.com/kb/HT213845", - "http://seclists.org/fulldisclosure/2023/Jul/47", - "https://bugs.openldap.org/show_bug.cgi?id=9904", - "https://security-tracker.debian.org/tracker/CVE-2023-2953", - "https://support.apple.com/kb/HT213844", - "https://access.redhat.com/security/cve/CVE-2023-2953", - "https://security.netapp.com/advisory/ntap-20230703-0005/", - "http://seclists.org/fulldisclosure/2023/Jul/52", - "https://support.apple.com/kb/HT213843" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-520865\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", - "severity": "Critical", - "type": "security", - "components": { - "deb://debian:bookworm:libexpat1:2.5.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", - "full_path": "libexpat1:2.5.0-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-632612", - "cves": [ - { - "cve": "CVE-2024-45492", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://github.com/libexpat/libexpat/issues/889", - "https://security-tracker.debian.org/tracker/CVE-2024-45492", - "https://github.com/libexpat/libexpat/pull/892" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-632612\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", - "severity": "Critical", - "type": "security", - "components": { - "deb://debian:bookworm:libexpat1:2.5.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", - "full_path": "libexpat1:2.5.0-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-632613", - "cves": [ - { - "cve": "CVE-2024-45490", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://github.com/libexpat/libexpat/issues/887", - "https://security-tracker.debian.org/tracker/CVE-2024-45490", - "https://github.com/libexpat/libexpat/pull/890" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-632613\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Xmlsoft Libxml2 v2.11.0 was discovered to contain an out-of-bounds read via the xmlSAX2StartElement() function at /libxml2/SAX2.c. This vulnerability allows attackers to cause a Denial of Service (DoS) via supplying a crafted XML file. NOTE: the vendor's position is that the product does not support the legacy SAX1 interface with custom callbacks; there is a crash even without crafted input.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1": { - "fixed_versions": [ - "[2.12.7+dfsg-1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1", - "full_path": "libxml2:2.9.14+dfsg-1.3~deb12u1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-529332", - "cves": [ - { - "cve": "CVE-2023-39615", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-39615", - "https://gitlab.gnome.org/GNOME/libxml2/-/issues/535" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-529332\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL\nto crash leading to a potential Denial of Service attack\n\nImpact summary: Applications loading files in the PKCS12 format from untrusted\nsources might terminate abruptly.\n\nA file in PKCS12 format can contain certificates and keys and may come from an\nuntrusted source. The PKCS12 specification allows certain fields to be NULL, but\nOpenSSL does not correctly check for this case. This can lead to a NULL pointer\ndereference that results in OpenSSL crashing. If an application processes PKCS12\nfiles from an untrusted source using the OpenSSL APIs then that application will\nbe vulnerable to this issue.\n\nOpenSSL APIs that are vulnerable to this are: PKCS12_parse(),\nPKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes()\nand PKCS12_newpass().\n\nWe have also fixed a similar issue in SMIME_write_PKCS7(). However since this\nfunction is related to writing data we do not consider it security significant.\n\nThe FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "fixed_versions": [ - "[3.0.13-1~deb12u1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-589396", - "cves": [ - { - "cve": "CVE-2024-0727", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://github.com/openssl/openssl/commit/d135eeab8a5dbf72b3da5240bab9ddb7678dbd2c", - "https://github.openssl.org/openssl/extended-releases/commit/03b3941d60c4bce58fab69a0c22377ab439bc0e8", - "https://security-tracker.debian.org/tracker/CVE-2024-0727", - "https://github.openssl.org/openssl/extended-releases/commit/aebaa5883e31122b404e450732dc833dc9dee539", - "https://www.openssl.org/news/secadv/20240125.txt", - "https://security.netapp.com/advisory/ntap-20240208-0006/", - "https://github.com/openssl/openssl/commit/775acfdbd0c6af9ac855f34969cdab0c0c90844a", - "https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2", - "http://www.openwall.com/lists/oss-security/2024/03/11/1" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589396\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "A flaw was found in libtiff. A specially crafted tiff file can lead to a segmentation fault due to a buffer overflow in the Fax3Encode function in libtiff/tif_fax3.c, resulting in a denial of service.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-523187", - "cves": [ - { - "cve": "CVE-2023-3618", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-3618", - "https://support.apple.com/kb/HT214036", - "https://bugzilla.redhat.com/show_bug.cgi?id=2215865", - "https://security.netapp.com/advisory/ntap-20230824-0012/", - "https://access.redhat.com/security/cve/CVE-2023-3618", - "https://support.apple.com/kb/HT214037", - "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", - "https://support.apple.com/kb/HT214038" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-523187\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Integer overflow in the ReadDirectory function in tiffdump.c in tiffdump in LibTIFF before 3.9.5 allows remote attackers to cause a denial of service (application crash) or possibly have unspecified other impact via a crafted TIFF file containing a directory data structure with many directory entries.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-36369", - "cves": [ - { - "cve": "CVE-2010-4665", - "cvss_v2_score": "4.3", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:N/A:P" - } - ], - "references": [ - "http://www.securityfocus.com/bid/47338", - "http://lists.fedoraproject.org/pipermail/package-announce/2011-April/058478.html", - "http://www.debian.org/security/2012/dsa-2552", - "http://lists.opensuse.org/opensuse-security-announce/2011-05/msg00005.html", - "https://security-tracker.debian.org/tracker/CVE-2010-4665", - "http://security.gentoo.org/glsa/glsa-201209-02.xml", - "http://secunia.com/advisories/44271", - "http://ubuntu.com/usn/usn-1416-1", - "http://bugzilla.maptools.org/show_bug.cgi?id=2218", - "https://bugzilla.redhat.com/show_bug.cgi?id=695887", - "http://www.remotesensing.org/libtiff/v3.9.5.html", - "http://secunia.com/advisories/50726", - "http://openwall.com/lists/oss-security/2011/04/12/10" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-36369\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "AOMedia v3.0.0 to v3.5.0 was discovered to contain an invalid read memory access via the component assign_frame_buffer_p in av1/common/av1_common_int.h.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libaom3:3.6.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libaom3:3.6.0-1", - "full_path": "libaom3:3.6.0-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-529506", - "cves": [ - { - "cve": "CVE-2023-39616", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://bugs.chromium.org/p/aomedia/issues/detail?id=3372#c3", - "https://security-tracker.debian.org/tracker/CVE-2023-39616" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-529506\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "Invalid pointer dereference in libaom leads to denial of service when encoding crafted video data with nondefault configuration options set.", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "The published exploit demonstrates DoS" - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The issue can be exploited by the `aomenc` CLI tool when called on arbitrary input file with the flag `--drop-frame=1` - \n`aomenc --passes=1 -h 1 -w 1 --drop-frame=1 --end-usage=cbr --buf-sz=1 -o /dev/null poc`\n \n\nAlternatively, the issue can be exploited through `libaom` when calling `aom_codec_enc_init` where the 3rd arg (`config`) has `dropframe_thresh == 1` + calling `aom_codec_encode` with external input to the 2nd arg (`img`)", - "is_positive": true - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "Exploiting the DoS via invocation of the `aomenc` CLI tool has minimal security impact, since exploitation will cause the `aomenc` forked utiliy process to crash (crashing a forked process has minimal security impact)\n\nThe issue can also be exploited via specific calls to `libaom`, however the configuration needed is extremely rare and crashing a video encoder usually does not have a high security impact.\n\nDebian classified this CVE as a \"minor issue\"", - "is_positive": true - } - ] - } - }, - { - "summary": "A heap-based buffer overflow was found in the __vsyslog_internal function of the glibc library. This function is called by the syslog and vsyslog functions. This issue occurs when the openlog function was not called, or called with the ident argument set to NULL, and the program name (the basename of argv[0]) is bigger than 1024 bytes, resulting in an application crash or local privilege escalation. This issue affects glibc 2.36 and newer.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-589627", - "cves": [ - { - "cve": "CVE-2023-6246", - "cvss_v3_score": "7.8", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D2FIH77VHY3KCRROCXOT6L27WMZXSJ2G/", - "https://security.netapp.com/advisory/ntap-20240216-0007/", - "https://security-tracker.debian.org/tracker/CVE-2023-6246", - "https://access.redhat.com/security/cve/CVE-2023-6246", - "http://packetstormsecurity.com/files/176931/glibc-qsort-Out-Of-Bounds-Read-Write.html", - "http://seclists.org/fulldisclosure/2024/Feb/5", - "https://www.openwall.com/lists/oss-security/2024/01/30/6", - "http://packetstormsecurity.com/files/176932/glibc-syslog-Heap-Based-Buffer-Overflow.html", - "https://bugzilla.redhat.com/show_bug.cgi?id=2249053", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MWQ6BZJ6CV5UAW4VZSKJ6TO4KIW2KWAQ/", - "https://security.gentoo.org/glsa/202402-01", - "http://seclists.org/fulldisclosure/2024/Feb/3" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589627\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "A heap buffer overflow in glibc may lead to local privilege escalation.", - "full_description": "[glibc](https://www.gnu.org/software/libc/) is the GNU C Library, a widely-used implementation of the C standard library.\n\nA vulnerability was identified in __vsyslog_internal(), which is called by the API functions `syslog()` and `vsyslog()` of glibc syslog functionality. Unprivileged users could gain full root access by manipulating syslog inputs.\n\nThe initial prerequisite for exploiting this local privilege escalation is a local SUID executable that contains calls to one of the vulnerable functions `syslog()` and `vsyslog()`. In order to exploit this, the attacker needs to control either argv[0], which typically holds the name of the program being executed, or the `openlog()` ident argument. \n\nAs explained in [Qualys’s research](https://qualys.com/2024/01/30/cve-2023-6246/syslog.txt), the identification string (LogTag) being NULL is essential for exploiting this issue. Thus, the `openlog()` function would need to either not be called, or called with NULL for the ident param for successful exploitation. \n\nIn Qualys’s research, they utilized a code path in the `su` program that doesn’t reach `openlog()`. Meaning the default user-controlled, argv[0] was used. Keep in mind another attack vector is possible in a different scenario when the user can control the ident arg of `openlog()`.\n\nSeeing as argv[0] is the name (path) of the running program, it is highly likely for a local attacker to be able to abuse this CVE for a local privilege escalation and unlikely that a remote attacker will have control over this argument for an RCE attack.\n\nQualys demonstrated a successful LPE exploit on Fedora. While no other public exploits are yet known, the threat landscape could evolve. It is likely possible to exploit this on other Linux distributions as well.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has multiple mentions in general media", - "description": "The vulnerability received extensive media coverage." - }, - { - "name": "The issue has a detailed technical explanation published, that can aid in exploit development", - "description": "This vulnerability has a through technical writeup, which also details an exploit." - }, - { - "name": "The prerequisites for exploiting the issue are either extremely common or nonexistent (always exploitable)", - "description": "As explained in the summary, the requirements to trigger the vulnerability are highly likely on default Linux machines that use a vulnerable version of glibc." - }, - { - "name": "The issue can only be exploited by an attacker that can execute code on the vulnerable machine (excluding exceedingly rare circumstances)", - "description": "This vulnerability requires local access to exploit. It is unlikely to be exploitable in remote scenarios as explained in the summary.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "This is a local privilege escalation vulnerability that could enable a local attacker to execute code as a root user." - } - ] - } - }, - { - "summary": "A segment fault (SEGV) flaw was found in libtiff that could be triggered by passing a crafted tiff file to the TIFFReadRGBATileExt() API. This flaw allows a remote attacker to cause a heap-buffer overflow, leading to a denial of service.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-589395", - "cves": [ - { - "cve": "CVE-2023-52356", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://access.redhat.com/errata/RHSA-2024:5079", - "https://support.apple.com/kb/HT214123", - "https://support.apple.com/kb/HT214118", - "http://seclists.org/fulldisclosure/2024/Jul/21", - "https://support.apple.com/kb/HT214122", - "https://support.apple.com/kb/HT214117", - "http://seclists.org/fulldisclosure/2024/Jul/20", - "http://seclists.org/fulldisclosure/2024/Jul/23", - "https://support.apple.com/kb/HT214116", - "http://seclists.org/fulldisclosure/2024/Jul/16", - "https://support.apple.com/kb/HT214119", - "https://support.apple.com/kb/HT214124", - "http://seclists.org/fulldisclosure/2024/Jul/17", - "https://support.apple.com/kb/HT214120", - "http://seclists.org/fulldisclosure/2024/Jul/19", - "http://seclists.org/fulldisclosure/2024/Jul/22", - "http://seclists.org/fulldisclosure/2024/Jul/18", - "https://lists.debian.org/debian-lts-announce/2024/03/msg00011.html", - "https://gitlab.com/libtiff/libtiff/-/issues/622", - "https://gitlab.com/libtiff/libtiff/-/merge_requests/546", - "https://security-tracker.debian.org/tracker/CVE-2023-52356", - "https://bugzilla.redhat.com/show_bug.cgi?id=2251344", - "https://access.redhat.com/security/cve/CVE-2023-52356" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589395\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "A heap buffer overflow in libtiff may lead to denial of service when parsing a crafted tiff image.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "To exploit the vulnerability, the attacker must be able to upload a maliciously crafted tiff image which will be parsed by the victim.", - "is_positive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS score does not reflect the contextual prerequisites required to exploit the vulnerability.", - "is_positive": true - } - ] - } - }, - { - "summary": "An integer overflow was found in the __vsyslog_internal function of the glibc library. This function is called by the syslog and vsyslog functions. This issue occurs when these functions are called with a very long message, leading to an incorrect calculation of the buffer size to store the message, resulting in undefined behavior. This issue affects glibc 2.37 and newer.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-589628", - "cves": [ - { - "cve": "CVE-2023-6780", - "cvss_v3_score": "5.3", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L" - } - ], - "references": [ - "http://seclists.org/fulldisclosure/2024/Feb/3", - "https://security.gentoo.org/glsa/202402-01", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MWQ6BZJ6CV5UAW4VZSKJ6TO4KIW2KWAQ/", - "https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D2FIH77VHY3KCRROCXOT6L27WMZXSJ2G/", - "http://packetstormsecurity.com/files/176932/glibc-syslog-Heap-Based-Buffer-Overflow.html", - "https://www.openwall.com/lists/oss-security/2024/01/30/6", - "https://access.redhat.com/security/cve/CVE-2023-6780", - "https://security-tracker.debian.org/tracker/CVE-2023-6780", - "https://bugzilla.redhat.com/show_bug.cgi?id=2254396" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589628\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the function UncompressedImageCodec::decode_uncompressed_image.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libheif1:1.15.1-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", - "full_path": "libheif1:1.15.1-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-540353", - "cves": [ - { - "cve": "CVE-2023-49460", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-49460", - "https://github.com/strukturag/libheif/issues/1046" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540353\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "A NULL pointer dereference in libheif may lead to denial of service when parsing crafted images.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "A proof-of-concept was published in the report's GitHub Issue." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "To successfully exploit this vulnerability an attacker needs to find a way to propagate input into the vulnerable `UncompressedImageCodec::decode_uncompressed_image` function.", - "is_positive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS score does not reflect the context dependent exploitation and impact of this vulnerability.", - "is_positive": true - } - ] - } - }, - { - "summary": "A null pointer dereference issue was found in Libtiff's tif_dir.c file. This issue may allow an attacker to pass a crafted TIFF image file to the tiffcp utility which triggers a runtime error that causes undefined behavior. This will result in an application crash, eventually leading to a denial of service.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-522698", - "cves": [ - { - "cve": "CVE-2023-2908", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://access.redhat.com/security/cve/CVE-2023-2908", - "https://gitlab.com/libtiff/libtiff/-/commit/9bd48f0dbd64fb94dc2b5b05238fde0bfdd4ff3f", - "https://gitlab.com/libtiff/libtiff/-/merge_requests/479", - "https://security.netapp.com/advisory/ntap-20230731-0004/", - "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", - "https://security-tracker.debian.org/tracker/CVE-2023-2908", - "https://bugzilla.redhat.com/show_bug.cgi?id=2218830" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-522698\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Multiple integer signedness errors in crypto/buffer/buffer.c in OpenSSL 0.9.8v allow remote attackers to conduct buffer overflow attacks, and cause a denial of service (memory corruption) or possibly have unspecified other impact, via crafted DER data, as demonstrated by an X.509 certificate or an RSA public key. NOTE: this vulnerability exists because of an incomplete fix for CVE-2012-2110.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-192416", - "cves": [ - { - "cve": "CVE-2012-2131", - "cvss_v2_score": "7.5", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P" - } - ], - "references": [ - "http://www.openwall.com/lists/oss-security/2012/04/24/1", - "http://secunia.com/advisories/48956", - "http://lists.apple.com/archives/security-announce/2013/Jun/msg00000.html", - "http://www.ubuntu.com/usn/USN-1428-1", - "http://secunia.com/advisories/48895", - "http://www-01.ibm.com/support/docview.wss?uid=ssg1S1004564", - "http://www.mandriva.com/security/advisories?name=MDVSA-2012:064", - "http://www.debian.org/security/2012/dsa-2454", - "http://www.openssl.org/news/secadv_20120424.txt", - "http://lists.opensuse.org/opensuse-security-announce/2012-05/msg00014.html", - "http://lists.opensuse.org/opensuse-security-announce/2012-09/msg00007.html", - "http://www.securitytracker.com/id?1026957", - "http://secunia.com/advisories/57353", - "http://marc.info/?l=bugtraq\u0026m=134039053214295\u0026w=2", - "https://security-tracker.debian.org/tracker/CVE-2012-2131", - "http://cvs.openssl.org/chngview?cn=22479", - "http://marc.info/?l=bugtraq\u0026m=133728068926468\u0026w=2", - "http://kb.juniper.net/InfoCenter/index?page=content\u0026id=JSA10673", - "https://exchange.xforce.ibmcloud.com/vulnerabilities/75099", - "http://www.securityfocus.com/bid/53212", - "http://lists.opensuse.org/opensuse-security-announce/2012-05/msg00015.html", - "http://support.apple.com/kb/HT5784" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-192416\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "A Segmentation fault caused by a floating point exception exists in libheif 1.15.1 using crafted heif images via the heif::Fraction::round() function in box.cc, which causes a denial of service.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libheif1:1.15.1-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", - "full_path": "libheif1:1.15.1-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-519184", - "cves": [ - { - "cve": "CVE-2023-29659", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/CKAE6NQBA3Q7GS6VTNDZRZZZVPPEFUEZ/", - "https://github.com/strukturag/libheif/issues/794", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LGKHDCS4HRZE3UGXYYDYPTIPNIBRLQ5L/", - "https://security-tracker.debian.org/tracker/CVE-2023-29659" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-519184\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "CPAN.pm before 2.35 does not verify TLS certificates when downloading distributions over HTTPS.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:perl-base:5.36.0-7": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:perl-base:5.36.0-7", - "full_path": "perl-base:5.36.0-7" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-515823", - "cves": [ - { - "cve": "CVE-2023-31484", - "cvss_v3_score": "8.1", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "http://www.openwall.com/lists/oss-security/2023/04/29/1", - "https://security.netapp.com/advisory/ntap-20240621-0007/", - "http://www.openwall.com/lists/oss-security/2023/05/03/5", - "http://www.openwall.com/lists/oss-security/2023/05/03/3", - "https://blog.hackeriet.no/perl-http-tiny-insecure-tls-default-affects-cpan-modules/", - "http://www.openwall.com/lists/oss-security/2023/05/07/2", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/BM6UW55CNFUTNGD5ZRKGUKKKFDJGMFHL/", - "https://metacpan.org/dist/CPAN/changes", - "https://security-tracker.debian.org/tracker/CVE-2023-31484", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LEGCEOKFJVBJ2QQ6S2H4NAEWTUERC7SB/", - "https://github.com/andk/cpanpm/pull/175", - "https://www.openwall.com/lists/oss-security/2023/04/18/14" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-515823\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "Missing TLS check in CPAN.pm allows man-in-the-middle attacks when downloading packages and may lead to code execution.", - "full_description": "[CPAN.pm](https://metacpan.org/pod/CPAN) is a Perl module and command-line tool that provides an automated and standardized way to download, install, and manage Perl modules and their dependencies from the Comprehensive Perl Archive Network (CPAN).\n[HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) is an HTTP client in Perl and a standalone CPAN module. By default, it does not verify TLS certificates. To enable it, the `verify_SSL=\u003e1` flag should be specified when initializing the `HTTP::Tiny` object. The problem identified in `HTTP::Tiny` has been assigned the CVE identifier `CVE-2023-31486` and serves as the underlying cause for the problem in `CPAN.pm`.\n\n`CPAN.pm` downloads and executes code through the `install` command followed by the package name.\nAlthough `CPAN.pm` downloads from `https://cpan.org`, it does not enable TLS certificate verification while using `HTTP::Tiny`, which could potentially allow an attacker to perform a man-in-the-middle attack by injecting malicious data that could be executed by CPAN.pm.\n\nExample of a vulnerable code:\n```\nuse CPAN;\ninstall DateTime\n```\n\nExample of a vulnerable command-line:\n```\ncpan install DateTime\n```", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue is trivial to exploit and does not require a published writeup or PoC", - "description": "Exploitation only requires an attacker to perform a man-in-the-middle attack (which is extensively documented) and provide the victim with a malicious package instead of the legitimate one." - }, - { - "name": "The issue has a detailed technical explanation published, that can aid in exploit development", - "description": "A technical write-up exists." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker should be in the network to perform a man-in-the-middle attack, and then provide a malicious package when the victim installs a new CPAN.pm package.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "This issue may lead to code execution." - }, - { - "name": "The issue can be exploited by attackers over the network" - } - ] - } - }, - { - "summary": "A vulnerability was found in systemd-resolved. This issue may allow systemd-resolved to accept records of DNSSEC-signed domains even when they have no signature, allowing man-in-the-middles (or the upstream DNS resolver) to manipulate records.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", - "full_path": "libsystemd0:252.17-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", - "full_path": "libudev1:252.17-1~deb12u1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-585478", - "cves": [ - { - "cve": "CVE-2023-7008", - "cvss_v3_score": "5.9", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N" - } - ], - "references": [ - "https://bugzilla.redhat.com/show_bug.cgi?id=2222672", - "https://github.com/systemd/systemd/issues/25676", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/4GMDEG5PKONWNHOEYSUDRT6JEOISRMN2/", - "https://access.redhat.com/errata/RHSA-2024:2463", - "https://access.redhat.com/security/cve/CVE-2023-7008", - "https://security-tracker.debian.org/tracker/CVE-2023-7008", - "https://access.redhat.com/errata/RHSA-2024:3203", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/QHNBXGKJWISJETTTDTZKTBFIBJUOSLKL/", - "https://bugzilla.redhat.com/show_bug.cgi?id=2222261" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-585478\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Issue summary: The POLY1305 MAC (message authentication code) implementation\ncontains a bug that might corrupt the internal state of applications running\non PowerPC CPU based platforms if the CPU provides vector instructions.\n\nImpact summary: If an attacker can influence whether the POLY1305 MAC\nalgorithm is used, the application state might be corrupted with various\napplication dependent consequences.\n\nThe POLY1305 MAC (message authentication code) implementation in OpenSSL for\nPowerPC CPUs restores the contents of vector registers in a different order\nthan they are saved. Thus the contents of some of these vector registers\nare corrupted when returning to the caller. The vulnerable code is used only\non newer PowerPC processors supporting the PowerISA 2.07 instructions.\n\nThe consequences of this kind of internal application state corruption can\nbe various - from no consequences, if the calling application does not\ndepend on the contents of non-volatile XMM registers at all, to the worst\nconsequences, where the attacker could get complete control of the application\nprocess. However unless the compiler uses the vector registers for storing\npointers, the most likely consequence, if any, would be an incorrect result\nof some application dependent calculations or a crash leading to a denial of\nservice.\n\nThe POLY1305 MAC algorithm is most frequently used as part of the\nCHACHA20-POLY1305 AEAD (authenticated encryption with associated data)\nalgorithm. The most common usage of this AEAD cipher is with TLS protocol\nversions 1.2 and 1.3. If this cipher is enabled on the server a malicious\nclient can influence whether this AEAD cipher is used. This implies that\nTLS server applications using OpenSSL can be potentially impacted. However\nwe are currently not aware of any concrete application that would be affected\nby this issue therefore we consider this a Low severity security issue.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "fixed_versions": [ - "[3.0.13-1~deb12u1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-588102", - "cves": [ - { - "cve": "CVE-2023-6129", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H" - } - ], - "references": [ - "https://security.netapp.com/advisory/ntap-20240426-0008/", - "https://security.netapp.com/advisory/ntap-20240426-0013/", - "http://www.openwall.com/lists/oss-security/2024/03/11/1", - "https://github.com/openssl/openssl/commit/f3fc5808fe9ff74042d639839610d03b8fdcc015", - "https://github.com/openssl/openssl/commit/050d26383d4e264966fb83428e72d5d48f402d35", - "https://security.netapp.com/advisory/ntap-20240216-0009/", - "https://www.openssl.org/news/secadv/20240109.txt", - "https://security-tracker.debian.org/tracker/CVE-2023-6129", - "https://github.com/openssl/openssl/commit/5b139f95c9a47a55a0c54100f3837b1eee942b04", - "https://security.netapp.com/advisory/ntap-20240503-0011/" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-588102\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Libde265 v1.0.14 was discovered to contain a heap-buffer-overflow vulnerability in the derive_spatial_luma_vector_prediction function at motion.cc.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-540366", - "cves": [ - { - "cve": "CVE-2023-49465", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://github.com/strukturag/libde265/issues/435", - "https://lists.debian.org/debian-lts-announce/2023/12/msg00022.html", - "https://security-tracker.debian.org/tracker/CVE-2023-49465" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540366\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "A non-proven heap buffer overflow in libde265 may lead to remote code execution when parsing attacker-supplied H.265 data.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "description": "The attacker must be able to provide remote input that will be parsed by H.265, for example - `./dec265 attacker_input`.\nThe exploit only works on a small percent of executions, since the impact of parsing a malicious Atari DEGAS Elite bitmap file is contingent on the current heap state.", - "is_positive": true - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Although a PoC was linked to the issue, the maintainer was not able to reproduce the corruption. In addition, the heap buffer overflow was not proven to be able to cause remote code execution.", - "is_positive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS does not take into account the non-trivial exploitation.", - "is_positive": true - } - ] - } - }, - { - "summary": "Libde265 v1.0.12 was discovered to contain multiple buffer overflows via the num_tile_columns and num_tile_row parameters in the function pic_parameter_set::dump.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-538327", - "cves": [ - { - "cve": "CVE-2023-43887", - "cvss_v3_score": "8.1", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H" - } - ], - "references": [ - "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html", - "https://security-tracker.debian.org/tracker/CVE-2023-43887", - "https://github.com/strukturag/libde265/issues/418", - "https://github.com/strukturag/libde265/commit/63b596c915977f038eafd7647d1db25488a8c133" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-538327\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "An out of bounds read in libde265 may lead to denial of service or data leakage when decoding attacker-supplied data in a non-default configuration.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker has to be able to decode crafted H.265 files with the non-default dump headers option enabled. For example - `./dec265 -d attacker_input`", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "The Github issue has a linked PoC." - }, - { - "name": "The issue has a detailed technical explanation published, that can aid in exploit development", - "description": "The Github issue carefully explains the vulnerability." - } - ] - } - }, - { - "summary": "**DISPUTED**A failure in the -fstack-protector feature in GCC-based toolchains \nthat target AArch64 allows an attacker to exploit an existing buffer \noverflow in dynamically-sized local variables in your application \nwithout this being detected. This stack-protector failure only applies \nto C99-style dynamically-sized local variables or those created using \nalloca(). The stack-protector operates as intended for statically-sized \nlocal variables.\n\nThe default behavior when the stack-protector \ndetects an overflow is to terminate your application, resulting in \ncontrolled loss of availability. An attacker who can exploit a buffer \noverflow without triggering the stack-protector might be able to change \nprogram flow control to cause an uncontrolled loss of availability or to\n go further and affect confidentiality or integrity. NOTE: The GCC project argues that this is a missed hardening bug and not a vulnerability by itself.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:gcc-12-base:12.2.0-14": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:gcc-12-base:12.2.0-14", - "full_path": "gcc-12-base:12.2.0-14" - } - ] - ] - }, - "deb://debian:bookworm:libgcc-s1:12.2.0-14": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libgcc-s1:12.2.0-14", - "full_path": "libgcc-s1:12.2.0-14" - } - ] - ] - }, - "deb://debian:bookworm:libstdc++6:12.2.0-14": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libstdc++6:12.2.0-14", - "full_path": "libstdc++6:12.2.0-14" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-531779", - "cves": [ - { - "cve": "CVE-2023-4039", - "cvss_v3_score": "4.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N" - } - ], - "references": [ - "https://github.com/metaredteam/external-disclosures/security/advisories/GHSA-x7ch-h5rf-w2mf", - "https://developer.arm.com/Arm%20Security%20Center/GCC%20Stack%20Protector%20Vulnerability%20AArch64", - "https://security-tracker.debian.org/tracker/CVE-2023-4039" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-531779\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Buffer Overflow vulnerability in strukturag libde265 v1.10.12 allows a local attacker to cause a denial of service via the slice_segment_header function in the slice.cc component.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-537162", - "cves": [ - { - "cve": "CVE-2023-47471", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://github.com/strukturag/libde265/commit/e36b4a1b0bafa53df47514c419d5be3e8916ebc7", - "https://security-tracker.debian.org/tracker/CVE-2023-47471", - "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html", - "https://github.com/strukturag/libde265/issues/426" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-537162\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "A memory leak flaw was found in Libtiff's tiffcrop utility. This issue occurs when tiffcrop operates on a TIFF image file, allowing an attacker to pass a crafted TIFF image file to tiffcrop utility, which causes this memory leak issue, resulting an application crash, eventually leading to a denial of service.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-532917", - "cves": [ - { - "cve": "CVE-2023-3576", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://access.redhat.com/security/cve/CVE-2023-3576", - "https://access.redhat.com/errata/RHSA-2023:6575", - "https://bugzilla.redhat.com/show_bug.cgi?id=2219340", - "https://lists.debian.org/debian-lts-announce/2024/03/msg00011.html", - "https://security-tracker.debian.org/tracker/CVE-2023-3576" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-532917\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "LibTIFF is vulnerable to an integer overflow. This flaw allows remote attackers to cause a denial of service (application crash) or possibly execute an arbitrary code via a crafted tiff image, which triggers a heap-based buffer overflow.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-529112", - "cves": [ - { - "cve": "CVE-2023-40745", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://access.redhat.com/security/cve/CVE-2023-40745", - "https://access.redhat.com/errata/RHSA-2024:2289", - "https://security-tracker.debian.org/tracker/CVE-2023-40745", - "https://security.netapp.com/advisory/ntap-20231110-0005/", - "https://bugzilla.redhat.com/show_bug.cgi?id=2235265" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-529112\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "An integer overflow in libtiff’s tiffcp may lead to remote code execution when parsing crafted images.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "For an attacker to exploit this vulnerability, `tiffcp` has to be invoked with the `-m` flag with an attacker-controlled value. In addition to this, the attacker has to be able to supply a crafted TIFF file as input.", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "A PoC which demonstrates denial of service was published along with the git issue." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "The vulnerability leads to denial of service and possibly remote code execution." - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Although integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", - "is_positive": true - } - ] - } - }, - { - "summary": "linux-pam (aka Linux PAM) before 1.6.0 allows attackers to cause a denial of service (blocked login process) via mkfifo because the openat call (for protect_dir) lacks O_DIRECTORY.", - "severity": "Medium", - "type": "security", - "components": { - "deb://debian:bookworm:libpam-modules-bin:1.5.2-6+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libpam-modules-bin:1.5.2-6+deb12u1", - "full_path": "libpam-modules-bin:1.5.2-6+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libpam-modules:1.5.2-6+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libpam-modules:1.5.2-6+deb12u1", - "full_path": "libpam-modules:1.5.2-6+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libpam-runtime:1.5.2-6+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libpam-runtime:1.5.2-6+deb12u1", - "full_path": "libpam-runtime:1.5.2-6+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libpam0g:1.5.2-6+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libpam0g:1.5.2-6+deb12u1", - "full_path": "libpam0g:1.5.2-6+deb12u1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-588807", - "cves": [ - { - "cve": "CVE-2024-22365", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "https://github.com/linux-pam/linux-pam", - "http://www.openwall.com/lists/oss-security/2024/01/18/3", - "https://github.com/linux-pam/linux-pam/commit/031bb5a5d0d950253b68138b498dc93be69a64cb", - "https://github.com/linux-pam/linux-pam/releases/tag/v1.6.0", - "https://security-tracker.debian.org/tracker/CVE-2024-22365" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-588807\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "An off-by-one heap-based buffer overflow was found in the __vsyslog_internal function of the glibc library. This function is called by the syslog and vsyslog functions. This issue occurs when these functions are called with a message bigger than INT_MAX bytes, leading to an incorrect calculation of the buffer size to store the message, resulting in an application crash. This issue affects glibc 2.37 and newer.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-589629", - "cves": [ - { - "cve": "CVE-2023-6779", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H" - } - ], - "references": [ - "http://seclists.org/fulldisclosure/2024/Feb/3", - "https://security.netapp.com/advisory/ntap-20240223-0006/", - "https://access.redhat.com/security/cve/CVE-2023-6779", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D2FIH77VHY3KCRROCXOT6L27WMZXSJ2G/", - "https://security-tracker.debian.org/tracker/CVE-2023-6779", - "https://www.openwall.com/lists/oss-security/2024/01/30/6", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MWQ6BZJ6CV5UAW4VZSKJ6TO4KIW2KWAQ/", - "https://bugzilla.redhat.com/show_bug.cgi?id=2254395", - "https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt", - "https://security.gentoo.org/glsa/202402-01", - "http://packetstormsecurity.com/files/176932/glibc-syslog-Heap-Based-Buffer-Overflow.html" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-589629\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1" - }, - { - "summary": "Libde265 v1.0.14 was discovered to contain a heap-buffer-overflow vulnerability in the derive_combined_bipredictive_merging_candidates function at motion.cc.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-540357", - "cves": [ - { - "cve": "CVE-2023-49467", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://github.com/strukturag/libde265/issues/434", - "https://security-tracker.debian.org/tracker/CVE-2023-49467", - "https://lists.debian.org/debian-lts-announce/2023/12/msg00022.html" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540357\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "An infinite loop in libde265 leads to DoS when parsing attacker-supplied H.265 data.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS does not take into account the non-trivial exploitation prerequisites. In addition, the CVSS alludes that remote code execution is possible, while in reality the worst impact of exploiting this issue is denial of service.", - "is_positive": true - }, - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "description": "The attacker must be able to provide remote input that will be parsed by H.265, for example - `./dec265 attacker_input`.", - "is_positive": true - } - ] - } - }, - { - "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the component /libheif/exif.cc.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:libheif1:1.15.1-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", - "full_path": "libheif1:1.15.1-1" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-540354", - "cves": [ - { - "cve": "CVE-2023-49462", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://github.com/strukturag/libheif/issues/1043", - "https://security-tracker.debian.org/tracker/CVE-2023-49462" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-540354\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "An integer overflow in libheif leads to denial of service.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "A proof-of-concept was published along with the vulnerability via (GitHub)[https://github.com/strukturag/libheif/issues/1043]." - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS score does not reflect the context dependent exploitation of this vulnerability.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "To successfully exploit this vulnerability an attacker needs to find a way to propagate input into the vulnerable functions `modify_exif_tag_if_it_exists(unsigned char*, unsigned int, unsigned short, unsigned short)` or `read_exif_orientation_tag(unsigned char const*, unsigned int)`.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Successful exploitation of this vulnerability leads to denial of service." - } - ] - } - }, - { - "summary": "A vulnerability was found in perl 5.30.0 through 5.38.0. This issue occurs when a crafted regular expression is compiled by perl, which can allow an attacker controlled byte buffer overflow in a heap allocated buffer.", - "severity": "High", - "type": "security", - "components": { - "deb://debian:bookworm:perl-base:5.36.0-7": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:perl-base:5.36.0-7", - "full_path": "perl-base:5.36.0-7" - } - ] - ] - } - }, - "watch_name": "Security_watch_1", - "issue_id": "XRAY-539839", - "cves": [ - { - "cve": "CVE-2023-47038", - "cvss_v3_score": "7.8", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" - } - ], - "references": [ - "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1056746", - "https://access.redhat.com/errata/RHSA-2024:3128", - "https://access.redhat.com/security/cve/CVE-2023-47038", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNEEWAACXQCEEAKSG7XX2D5YDRWLCIZJ/", - "https://security-tracker.debian.org/tracker/CVE-2023-47038", - "https://bugzilla.redhat.com/show_bug.cgi?id=2249523", - "https://perldoc.perl.org/perl5382delta#CVE-2023-47038-Write-past-buffer-end-via-illegal-user-defined-Unicode-property", - "https://access.redhat.com/errata/RHSA-2024:2228" - ], - "ignore_url": "https://tokyoshiftleft.jfrog.io/ui/admin/xray/policiesGovernance/ignore-rules?graph_scan_id=f1ca2a08-1d7b-4194-72be-7b84afc51fac\u0026issue_id=XRAY-539839\u0026on_demand_scanning=true\u0026show_popup=true\u0026type=security\u0026watch_name=Security_watch_1", - "extended_information": { - "short_description": "(non-issue) A heap buffer overflow in Perl leads to no impact when parsing a crafted regular expression.", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "A test case is given, and is included in the Debian advisory:\n`perl -e 'qr/\\p{utf8::_perl_surrogate}/'`" - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "If the attacker can execute arbitrary Perl code, exploiting the vulnerability would offer no additional security impact.", - "is_positive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS impact does not reflect the prerequisites required to exploit the vulnerability.", - "is_positive": true - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "The attacker must be able to run Perl code which the victim executes.", - "is_positive": true - } - ] - } - } - ], - "vulnerabilities": [ - { - "cves": [ - { - "cve": "CVE-2019-3815", - "cvss_v2_score": "2.1", - "cvss_v2_vector": "CVSS:2.0/AV:L/AC:L/Au:N/C:N/I:N/A:P", - "cvss_v3_score": "3.3", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L", - "cwe": [ - "CWE-401" - ], - "cwe_details": { - "CWE-401": { - "name": "Missing Release of Memory after Effective Lifetime", - "description": "The product does not sufficiently track and release allocated memory after it has been used, which slowly consumes remaining memory." - } - } - } - ], - "summary": "A memory leak was discovered in the backport of fixes for CVE-2018-16864 in Red Hat Enterprise Linux. Function dispatch_message_real() in journald-server.c does not free the memory allocated by set_iovec_field_free() to store the `_CMDLINE=` entry. A local attacker may use this flaw to make systemd-journald crash. This issue only affects versions shipped with Red Hat Enterprise since v219-62.2.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", - "full_path": "libsystemd0:252.17-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", - "full_path": "libudev1:252.17-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-74739", - "references": [ - "https://access.redhat.com/errata/RHSA-2019:0201", - "https://lists.debian.org/debian-lts-announce/2019/03/msg00013.html", - "https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2019-3815", - "https://security-tracker.debian.org/tracker/CVE-2019-3815", - "https://access.redhat.com/errata/RHBA-2019:0327", - "http://www.securityfocus.com/bid/106632" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-50387", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-770" - ], - "cwe_details": { - "CWE-770": { - "name": "Allocation of Resources Without Limits or Throttling", - "description": "The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor." - } - } - } - ], - "summary": "Certain DNSSEC aspects of the DNS protocol (in RFC 4033, 4034, 4035, 6840, and related RFCs) allow remote attackers to cause a denial of service (CPU consumption) via one or more DNSSEC responses, aka the \"KeyTrap\" issue. One of the concerns is that, when there is a zone with many DNSKEY and RRSIG records, the protocol specification implies that an algorithm must evaluate all combinations of DNSKEY and RRSIG records.", - "severity": "High", - "components": { - "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", - "full_path": "libsystemd0:252.17-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", - "full_path": "libudev1:252.17-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-590537", - "references": [ - "https://security.netapp.com/advisory/ntap-20240307-0007/", - "http://www.openwall.com/lists/oss-security/2024/02/16/2", - "https://www.theregister.com/2024/02/13/dnssec_vulnerability_internet/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/6FV5O347JTX7P5OZA6NGO4MKTXRXMKOZ/", - "https://news.ycombinator.com/item?id=39367411", - "https://www.athene-center.de/aktuelles/key-trap", - "https://nlnetlabs.nl/news/2024/Feb/13/unbound-1.19.1-released/", - "https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2024q1/017430.html", - "https://www.isc.org/blogs/2024-bind-security-release/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/ZDZFMEKQTZ4L7RY46FCENWFB5MDT263R/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/RGS7JN6FZXUSTC2XKQHH27574XOULYYJ/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/TEXGOYGW7DBS3N2QSSQONZ4ENIRQEAPG/", - "https://bugzilla.suse.com/show_bug.cgi?id=1219823", - "https://lists.debian.org/debian-lts-announce/2024/05/msg00011.html", - "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-50387", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/HVRDSJVZKMCXKKPP6PNR62T7RWZ3YSDZ/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/PNNHZSZPG2E7NBMBNYPGHCFI4V4XRWNQ/", - "https://gitlab.nic.cz/knot/knot-resolver/-/releases/v5.7.1", - "https://www.athene-center.de/fileadmin/content/PDF/Technical_Report_KeyTrap.pdf", - "https://www.securityweek.com/keytrap-dns-attack-could-disable-large-parts-of-internet-researchers/", - "https://lists.debian.org/debian-lts-announce/2024/02/msg00006.html", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/SVYA42BLXUCIDLD35YIJPJSHDIADNYMP/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/BUIP7T7Z4T3UHLXFWG6XIVDP4GYPD3AI/", - "https://security-tracker.debian.org/tracker/CVE-2023-50387", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/IGSLGKUAQTW5JPPZCMF5YPEYALLRUZZ6/", - "https://kb.isc.org/docs/cve-2023-50387", - "https://docs.powerdns.com/recursor/security-advisories/powerdns-advisory-2024-01.html", - "https://news.ycombinator.com/item?id=39372384", - "http://www.openwall.com/lists/oss-security/2024/02/16/3", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/UQESRWMJCF4JEYJEAKLRM6CT55GLJAB7/", - "https://access.redhat.com/security/cve/CVE-2023-50387" - ], - "extended_information": { - "short_description": "Unbounded resource consumption in the DNSSEC extension of the DNS protocol may lead to denial of service when resolving a malicious domain.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are either extremely common or nonexistent (always exploitable)", - "description": "To exploit the vulnerability, an attacker needs to make the victim resolver validate his malicious domain.\nNote - This flaw is derived from the DNSSEC standard, thus every implementation of DNSSEC that follows the standard is vulnerable." - }, - { - "name": "The issue can be exploited by attackers over the network", - "description": "The attacker needs to send a DNS query to the target resolver, requesting his malicious domain. The attack occurs when the resolver tries to validate the response from the DNS server." - }, - { - "name": "The issue has an exploit published", - "description": "A PoC was published, demonstrating denial of service." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Exploitation of the vulnerability causes high resource consumption, which leads to denial of service." - }, - { - "name": "The issue has a detailed technical explanation published, that can aid in exploit development", - "description": "A technically detailed writeup of this vulnerability (under the name \"keytrap\") was published by the research team, ATHENE-RESEARC." - } - ], - "remediation": "##### Deployment mitigations\n\nSince the vulnerability affects many different DNS resolvers, remediation is on a case-by-case basis." - } - }, - { - "cves": [ - { - "cve": "CVE-2023-31437", - "cvss_v3_score": "5.3", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", - "cwe": [ - "CWE-354" - ], - "cwe_details": { - "CWE-354": { - "name": "Improper Validation of Integrity Check Value", - "description": "The product does not validate or incorrectly validates the integrity check values or checksums of a message. This may prevent it from detecting if the data has been modified or corrupted in transmission." - } - } - } - ], - "summary": "An issue was discovered in systemd 253. An attacker can modify a sealed log file such that, in some views, not all existing and sealed log messages are displayed. NOTE: the vendor reportedly sent \"a reply denying that any of the finding was a security vulnerability.\"", - "severity": "Low", - "components": { - "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", - "full_path": "libsystemd0:252.17-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", - "full_path": "libudev1:252.17-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-522311", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-31437", - "https://github.com/systemd/systemd/releases", - "https://github.com/kastel-security/Journald/blob/main/journald-publication.pdf", - "https://github.com/kastel-security/Journald" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-31439", - "cvss_v3_score": "5.3", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", - "cwe": [ - "CWE-354" - ], - "cwe_details": { - "CWE-354": { - "name": "Improper Validation of Integrity Check Value", - "description": "The product does not validate or incorrectly validates the integrity check values or checksums of a message. This may prevent it from detecting if the data has been modified or corrupted in transmission." - } - } - } - ], - "summary": "An issue was discovered in systemd 253. An attacker can modify the contents of past events in a sealed log file and then adjust the file such that checking the integrity shows no error, despite modifications. NOTE: the vendor reportedly sent \"a reply denying that any of the finding was a security vulnerability.\"", - "severity": "Low", - "components": { - "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", - "full_path": "libsystemd0:252.17-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", - "full_path": "libudev1:252.17-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-522310", - "references": [ - "https://github.com/kastel-security/Journald/blob/main/journald-publication.pdf", - "https://github.com/systemd/systemd/releases", - "https://github.com/systemd/systemd/pull/28885", - "https://security-tracker.debian.org/tracker/CVE-2023-31439", - "https://github.com/kastel-security/Journald" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-7008", - "cvss_v3_score": "5.9", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N", - "cwe": [ - "NVD-CWE-Other" - ] - } - ], - "summary": "A vulnerability was found in systemd-resolved. This issue may allow systemd-resolved to accept records of DNSSEC-signed domains even when they have no signature, allowing man-in-the-middles (or the upstream DNS resolver) to manipulate records.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", - "full_path": "libsystemd0:252.17-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", - "full_path": "libudev1:252.17-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-585478", - "references": [ - "https://bugzilla.redhat.com/show_bug.cgi?id=2222672", - "https://github.com/systemd/systemd/issues/25676", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/4GMDEG5PKONWNHOEYSUDRT6JEOISRMN2/", - "https://access.redhat.com/errata/RHSA-2024:2463", - "https://access.redhat.com/security/cve/CVE-2023-7008", - "https://security-tracker.debian.org/tracker/CVE-2023-7008", - "https://access.redhat.com/errata/RHSA-2024:3203", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/QHNBXGKJWISJETTTDTZKTBFIBJUOSLKL/", - "https://bugzilla.redhat.com/show_bug.cgi?id=2222261" - ] - }, - { - "cves": [ - { - "cve": "CVE-2013-4392", - "cvss_v2_score": "3.3", - "cvss_v2_vector": "CVSS:2.0/AV:L/AC:M/Au:N/C:P/I:P/A:N", - "cwe": [ - "CWE-59" - ], - "cwe_details": { - "CWE-59": { - "name": "Improper Link Resolution Before File Access ('Link Following')", - "description": "The product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource." - } - } - } - ], - "summary": "systemd, when updating file permissions, allows local users to change the permissions and SELinux security contexts for arbitrary files via a symlink attack on unspecified files.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", - "full_path": "libsystemd0:252.17-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", - "full_path": "libudev1:252.17-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-32874", - "references": [ - "http://www.openwall.com/lists/oss-security/2013/10/01/9", - "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=725357", - "https://security-tracker.debian.org/tracker/CVE-2013-4392", - "https://bugzilla.redhat.com/show_bug.cgi?id=859060" - ], - "extended_information": { - "short_description": "Improper update of SELinux labels in systemd allows root users to bypass SELinux via mount commands.", - "full_description": "[`systemd`](https://systemd.io) is a Linux software suite that provides numerous tools and system components, mainly a system and service manager, who runs on system startup.\n`systemd` before 239 improperly performs [`SELinux`](https://selinuxproject.org/) label updates when mounting drives, which makes it vulnerable to symlink attacks that may result in local privilege escalation. \n\n`SELinux` labels are used for access control, and help manage the access to resources based on user privilege. When `systemd` is required to mount user-specified drives or directories, it recursively updates the `SELinux` labels of the files inside the mounted directory tree, granting privileges to the mounting user to use those files. A vulnerability in `systemd`'s `label_fix` function allows an attacker to perform a symlink attack, in which a symlink to a sensitive resource exists in the mounted directory tree. This would result in the update of the `SELinux` label of the file pointed by the symlink, granting the mounting user privileges to use that resource, effectively bypassing SELinux.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are either extremely common or nonexistent (always exploitable)", - "description": "The issue affects many distributions by default, when SELinux is enabled" - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "Bypass of SELinux by root users", - "is_positive": true - }, - { - "name": "The issue can only be exploited by an attacker that can execute code on the vulnerable machine (excluding exceedingly rare circumstances)", - "description": "A local attacker must create symbolic links and perform mount commands", - "is_positive": true - }, - { - "name": "The issue can only be exploited by an attacker with high privileges", - "description": "Mounting requires root privileges", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-31438", - "cvss_v3_score": "5.3", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", - "cwe": [ - "CWE-354" - ], - "cwe_details": { - "CWE-354": { - "name": "Improper Validation of Integrity Check Value", - "description": "The product does not validate or incorrectly validates the integrity check values or checksums of a message. This may prevent it from detecting if the data has been modified or corrupted in transmission." - } - } - } - ], - "summary": "An issue was discovered in systemd 253. An attacker can truncate a sealed log file and then resume log sealing such that checking the integrity shows no error, despite modifications. NOTE: the vendor reportedly sent \"a reply denying that any of the finding was a security vulnerability.\"", - "severity": "Low", - "components": { - "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libsystemd0:252.17-1~deb12u1", - "full_path": "libsystemd0:252.17-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libudev1:252.17-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libudev1:252.17-1~deb12u1", - "full_path": "libudev1:252.17-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-522309", - "references": [ - "https://github.com/kastel-security/Journald", - "https://github.com/systemd/systemd/releases", - "https://github.com/kastel-security/Journald/blob/main/journald-publication.pdf", - "https://security-tracker.debian.org/tracker/CVE-2023-31438", - "https://github.com/systemd/systemd/pull/28886" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-50495", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "NVD-CWE-noinfo" - ] - } - ], - "summary": "NCurse v6.4-20230418 was discovered to contain a segmentation fault via the component _nc_wrap_entry().", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libtinfo6:6.4-4": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libtinfo6:6.4-4", - "full_path": "libtinfo6:6.4-4" - } - ] - ] - }, - "deb://debian:bookworm:ncurses-base:6.4-4": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:ncurses-base:6.4-4", - "full_path": "ncurses-base:6.4-4" - } - ] - ] - }, - "deb://debian:bookworm:ncurses-bin:6.4-4": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:ncurses-bin:6.4-4", - "full_path": "ncurses-bin:6.4-4" - } - ] - ] - } - }, - "issue_id": "XRAY-540521", - "references": [ - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LU4MYMKFEZQ5VSCVLRIZGDQOUW3T44GT/", - "https://lists.gnu.org/archive/html/bug-ncurses/2023-04/msg00020.html", - "https://security.netapp.com/advisory/ntap-20240119-0008/", - "https://security-tracker.debian.org/tracker/CVE-2023-50495", - "https://lists.gnu.org/archive/html/bug-ncurses/2023-04/msg00029.html" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-2379" - } - ], - "summary": "libcurl skips the certificate verification for a QUIC connection under certain conditions, when built to use wolfSSL. If told to use an unknown/bad cipher or curve, the error path accidentally skips the verification and returns OK, thus ignoring any certificate problems.", - "severity": "Low", - "components": { - "deb://debian:bookworm:curl:7.88.1-10+deb12u4": { - "fixed_versions": [ - "[8.7.1-1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:curl:7.88.1-10+deb12u4", - "full_path": "curl:7.88.1-10+deb12u4" - } - ] - ] - }, - "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4", - "full_path": "libcurl4:7.88.1-10+deb12u4" - } - ] - ] - } - }, - "issue_id": "XRAY-596170", - "references": [ - "https://curl.se/docs/CVE-2024-2379.html", - "https://support.apple.com/kb/HT214120", - "https://support.apple.com/kb/HT214118", - "http://seclists.org/fulldisclosure/2024/Jul/19", - "https://support.apple.com/kb/HT214119", - "http://seclists.org/fulldisclosure/2024/Jul/18", - "http://seclists.org/fulldisclosure/2024/Jul/20", - "http://www.openwall.com/lists/oss-security/2024/03/27/2", - "https://hackerone.com/reports/2410774", - "https://security.netapp.com/advisory/ntap-20240531-0001/", - "https://security-tracker.debian.org/tracker/CVE-2024-2379", - "https://curl.se/docs/CVE-2024-2379.json" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-46219", - "cvss_v3_score": "5.3", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", - "cwe": [ - "CWE-311" - ], - "cwe_details": { - "CWE-311": { - "name": "Missing Encryption of Sensitive Data", - "description": "The product does not encrypt sensitive or critical information before storage or transmission." - } - } - } - ], - "summary": "When saving HSTS data to an excessively long file name, curl could end up\nremoving all contents, making subsequent requests using that file unaware of\nthe HSTS status they should otherwise use.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:curl:7.88.1-10+deb12u4": { - "fixed_versions": [ - "[7.88.1-10+deb12u5]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:curl:7.88.1-10+deb12u4", - "full_path": "curl:7.88.1-10+deb12u4" - } - ] - ] - }, - "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4", - "full_path": "libcurl4:7.88.1-10+deb12u4" - } - ] - ] - } - }, - "issue_id": "XRAY-540277", - "references": [ - "https://www.debian.org/security/2023/dsa-5587", - "https://security.netapp.com/advisory/ntap-20240119-0007/", - "https://hackerone.com/reports/2236133", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UOGXU25FMMT2X6UUITQ7EZZYMJ42YWWD/", - "https://curl.se/docs/CVE-2023-46219.html", - "https://security-tracker.debian.org/tracker/CVE-2023-46219" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-7264", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-125" - ], - "cwe_details": { - "CWE-125": { - "name": "Out-of-bounds Read", - "description": "The product reads data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "7" - } - ] - } - } - } - ], - "summary": "libcurl's ASN1 parser code has the `GTime2str()` function, used for parsing an\nASN.1 Generalized Time field. If given an syntactically incorrect field, the\nparser might end up using -1 for the length of the *time fraction*, leading to\na `strlen()` getting performed on a pointer to a heap buffer area that is not\n(purposely) null terminated.\n\nThis flaw most likely leads to a crash, but can also lead to heap contents\ngetting returned to the application when\n[CURLINFO_CERTINFO](https://curl.se/libcurl/c/CURLINFO_CERTINFO.html) is used.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:curl:7.88.1-10+deb12u4": { - "fixed_versions": [ - "[7.88.1-10+deb12u7]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:curl:7.88.1-10+deb12u4", - "full_path": "curl:7.88.1-10+deb12u4" - } - ] - ] - }, - "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4", - "full_path": "libcurl4:7.88.1-10+deb12u4" - } - ] - ] - } - }, - "issue_id": "XRAY-617171", - "references": [ - "https://hackerone.com/reports/2629968", - "https://security-tracker.debian.org/tracker/CVE-2024-7264", - "https://curl.se/docs/CVE-2024-7264.json", - "http://www.openwall.com/lists/oss-security/2024/07/31/1", - "https://curl.se/docs/CVE-2024-7264.html" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-46218", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N", - "cwe": [ - "NVD-CWE-noinfo" - ] - } - ], - "summary": "This flaw allows a malicious HTTP server to set \"super cookies\" in curl that\nare then passed back to more origins than what is otherwise allowed or\npossible. This allows a site to set cookies that then would get sent to\ndifferent and unrelated sites and domains.\n\nIt could do this by exploiting a mixed case flaw in curl's function that\nverifies a given cookie domain against the Public Suffix List (PSL). For\nexample a cookie could be set with `domain=co.UK` when the URL used a lower\ncase hostname `curl.co.uk`, even though `co.uk` is listed as a PSL domain.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:curl:7.88.1-10+deb12u4": { - "fixed_versions": [ - "[7.88.1-10+deb12u5]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:curl:7.88.1-10+deb12u4", - "full_path": "curl:7.88.1-10+deb12u4" - } - ] - ] - }, - "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libcurl4:7.88.1-10+deb12u4", - "full_path": "libcurl4:7.88.1-10+deb12u4" - } - ] - ] - } - }, - "issue_id": "XRAY-540279", - "references": [ - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/3ZX3VW67N4ACRAPMV2QS2LVYGD7H2MVE/", - "https://security-tracker.debian.org/tracker/CVE-2023-46218", - "https://lists.debian.org/debian-lts-announce/2023/12/msg00015.html", - "https://curl.se/docs/CVE-2023-46218.html", - "https://hackerone.com/reports/2212193", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UOGXU25FMMT2X6UUITQ7EZZYMJ42YWWD/", - "https://security.netapp.com/advisory/ntap-20240125-0007/", - "https://www.debian.org/security/2023/dsa-5587" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-3618", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-120" - ], - "cwe_details": { - "CWE-120": { - "name": "Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')", - "description": "The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow." - } - } - } - ], - "summary": "A flaw was found in libtiff. A specially crafted tiff file can lead to a segmentation fault due to a buffer overflow in the Fax3Encode function in libtiff/tif_fax3.c, resulting in a denial of service.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-523187", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-3618", - "https://support.apple.com/kb/HT214036", - "https://bugzilla.redhat.com/show_bug.cgi?id=2215865", - "https://security.netapp.com/advisory/ntap-20230824-0012/", - "https://access.redhat.com/security/cve/CVE-2023-3618", - "https://support.apple.com/kb/HT214037", - "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", - "https://support.apple.com/kb/HT214038" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-26965", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "loadImage() in tools/tiffcrop.c in LibTIFF through 4.5.0 has a heap-based use after free via a crafted TIFF image.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-522607", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-26965", - "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", - "https://security.netapp.com/advisory/ntap-20230706-0009/", - "https://gitlab.com/libtiff/libtiff/-/merge_requests/472" - ], - "extended_information": { - "short_description": "Use after free in libtiff's Tiffcrop may lead to code execution when parsing crafted images.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "Published PoC demonstrates crashing the tiffcrop CLI utility. Note that crashing tiffcrop has no security impact, since it is a forked CLI utility (will not crash parent process)." - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Although a crashing PoC is available, exploiting the vulnerability for remote code execution is currently only theoretically possible, and actual exploitation has not been demonstrated. Only some cases of use-after-free can be exploited for RCE.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker must be able to upload a crafted TIFF image, which will then be processed by the `tiffcrop` CLI tool, for example -\n```bash\ntiffcrop -z 12,50,12,99:112,150,112,199 -e divided attacker_image.tiff output.tiff\n```", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2022-3636", - "cvss_v3_score": "7.8", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-119" - ], - "cwe_details": { - "CWE-119": { - "name": "Improper Restriction of Operations within the Bounds of a Memory Buffer", - "description": "The product performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "17" - } - ] - } - } - } - ], - "summary": "A vulnerability, which was classified as critical, was found in Linux Kernel. This affects the function __mtk_ppe_check_skb of the file drivers/net/ethernet/mediatek/mtk_ppe.c of the component Ethernet Handler. The manipulation leads to use after free. It is recommended to apply a patch to fix this issue. The associated identifier of this vulnerability is VDB-211935.", - "severity": "High", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-414609", - "references": [ - "https://git.kernel.org/pub/scm/linux/kernel/git/pabeni/net-next.git/commit/?id=17a5f6a78dc7b8db385de346092d7d9f9dc24df6", - "https://vuldb.com/?id.211935", - "https://www.debian.org/security/2023/dsa-5333", - "https://security-tracker.debian.org/tracker/CVE-2022-3636" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-6277", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-400" - ], - "cwe_details": { - "CWE-400": { - "name": "Uncontrolled Resource Consumption", - "description": "The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources." - } - } - } - ], - "summary": "An out-of-memory flaw was found in libtiff. Passing a crafted tiff file to TIFFOpen() API may allow a remote attacker to cause a denial of service via a craft input with size smaller than 379 KB.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-539830", - "references": [ - "https://gitlab.com/libtiff/libtiff/-/issues/614", - "https://support.apple.com/kb/HT214123", - "https://support.apple.com/kb/HT214118", - "https://support.apple.com/kb/HT214122", - "https://support.apple.com/kb/HT214120", - "http://seclists.org/fulldisclosure/2024/Jul/21", - "http://seclists.org/fulldisclosure/2024/Jul/19", - "https://support.apple.com/kb/HT214117", - "http://seclists.org/fulldisclosure/2024/Jul/20", - "http://seclists.org/fulldisclosure/2024/Jul/23", - "https://support.apple.com/kb/HT214116", - "http://seclists.org/fulldisclosure/2024/Jul/16", - "https://support.apple.com/kb/HT214119", - "https://support.apple.com/kb/HT214124", - "http://seclists.org/fulldisclosure/2024/Jul/17", - "http://seclists.org/fulldisclosure/2024/Jul/22", - "http://seclists.org/fulldisclosure/2024/Jul/18", - "https://security.netapp.com/advisory/ntap-20240119-0002/", - "https://access.redhat.com/security/cve/CVE-2023-6277", - "https://bugzilla.redhat.com/show_bug.cgi?id=2251311", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/Y7ZGN2MZXJ6E57W3L4YBM3ZPAU3T7T5C/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/WJIN6DTSL3VODZUGWEUXLEL5DR53EZMV/", - "https://security-tracker.debian.org/tracker/CVE-2023-6277", - "https://gitlab.com/libtiff/libtiff/-/merge_requests/545" - ] - }, - { - "cves": [ - { - "cve": "CVE-2017-16232", - "cvss_v2_score": "5.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-772" - ], - "cwe_details": { - "CWE-772": { - "name": "Missing Release of Resource after Effective Lifetime", - "description": "The product does not release a resource after its effective lifetime has ended, i.e., after the resource is no longer needed." - } - } - } - ], - "summary": "LibTIFF 4.0.8 has multiple memory leak vulnerabilities, which allow attackers to cause a denial of service (memory consumption), as demonstrated by tif_open.c, tif_lzw.c, and tif_aux.c. NOTE: Third parties were unable to reproduce the issue", - "severity": "Low", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-59579", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2017-16232", - "http://lists.opensuse.org/opensuse-security-announce/2018-01/msg00036.html", - "http://www.securityfocus.com/bid/101696", - "http://seclists.org/fulldisclosure/2018/Dec/47", - "http://www.openwall.com/lists/oss-security/2017/11/01/7", - "http://seclists.org/fulldisclosure/2018/Dec/32", - "http://www.openwall.com/lists/oss-security/2017/11/01/3", - "http://packetstormsecurity.com/files/150896/LibTIFF-4.0.8-Memory-Leak.html", - "http://lists.opensuse.org/opensuse-security-announce/2018-01/msg00041.html", - "http://www.openwall.com/lists/oss-security/2017/11/01/8", - "http://www.openwall.com/lists/oss-security/2017/11/01/11" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-2908", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-476" - ], - "cwe_details": { - "CWE-476": { - "name": "NULL Pointer Dereference", - "description": "A NULL pointer dereference occurs when the application dereferences a pointer that it expects to be valid, but is NULL, typically causing a crash or exit.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "12" - } - ] - } - } - } - ], - "summary": "A null pointer dereference issue was found in Libtiff's tif_dir.c file. This issue may allow an attacker to pass a crafted TIFF image file to the tiffcp utility which triggers a runtime error that causes undefined behavior. This will result in an application crash, eventually leading to a denial of service.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-522698", - "references": [ - "https://access.redhat.com/security/cve/CVE-2023-2908", - "https://gitlab.com/libtiff/libtiff/-/commit/9bd48f0dbd64fb94dc2b5b05238fde0bfdd4ff3f", - "https://gitlab.com/libtiff/libtiff/-/merge_requests/479", - "https://security.netapp.com/advisory/ntap-20230731-0004/", - "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", - "https://security-tracker.debian.org/tracker/CVE-2023-2908", - "https://bugzilla.redhat.com/show_bug.cgi?id=2218830" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-26966", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-120" - ], - "cwe_details": { - "CWE-120": { - "name": "Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')", - "description": "The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow." - } - } - } - ], - "summary": "libtiff 4.5.0 is vulnerable to Buffer Overflow in uv_encode() when libtiff reads a corrupted little-endian TIFF file and specifies the output to be big-endian.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-522650", - "references": [ - "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html", - "https://security-tracker.debian.org/tracker/CVE-2023-26966", - "https://gitlab.com/libtiff/libtiff/-/issues/530", - "https://gitlab.com/libtiff/libtiff/-/merge_requests/473" - ] - }, - { - "cves": [ - { - "cve": "CVE-2017-17973", - "cvss_v2_score": "6.8", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:P/I:P/A:P", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-416" - ], - "cwe_details": { - "CWE-416": { - "name": "Use After Free", - "description": "Referencing memory after it has been freed can cause a program to crash, use unexpected values, or execute code.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "4" - } - ] - } - } - } - ], - "summary": "In LibTIFF 4.0.8, there is a heap-based use-after-free in the t2p_writeproc function in tiff2pdf.c. NOTE: there is a third-party report of inability to reproduce this issue", - "severity": "Low", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-60516", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2017-17973", - "https://bugzilla.novell.com/show_bug.cgi?id=1074318", - "http://www.securityfocus.com/bid/102331", - "https://bugzilla.redhat.com/show_bug.cgi?id=1530912", - "http://bugzilla.maptools.org/show_bug.cgi?id=2769" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-52355", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "An out-of-memory flaw was found in libtiff that could be triggered by passing a crafted tiff file to the TIFFRasterScanlineSize64() API. This flaw allows a remote attacker to cause a denial of service via a crafted input with a size smaller than 379 KB.", - "severity": "High", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-589394", - "references": [ - "https://gitlab.com/libtiff/libtiff/-/issues/621", - "https://security-tracker.debian.org/tracker/CVE-2023-52355", - "https://bugzilla.redhat.com/show_bug.cgi?id=2251326", - "https://access.redhat.com/security/cve/CVE-2023-52355" - ], - "extended_information": { - "short_description": "Unbounded resource consumption in libtiff may lead to denial of service when parsing a crafted tiff file.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "PoC is included in the git issue discussing the problem." - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS attack complexity does not reflect the contextual prerequisites required to exploit the vulnerability.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "To exploit the vulnerability, the attacker must be able to upload a tiff file whose size will get checked by the vulnerable `TIFFRasterScanlineSize64()` function, and allocate memory (without any limitations) based on the results.", - "is_positive": true - } - ], - "remediation": "##### Development mitigations\n\nAs a workaround, users could implement checks, or use `TIFFOpenOptionsSetMaxSingleMemAlloc()`, to reject files that they consider to consume too many resources for their use case. For example -\n```\n// Allow 1MB single mem alloc\nTIFFOpenOptionsSetMaxSingleMemAlloc(\u0026opts, 1*1024*1024);\n```" - } - }, - { - "cves": [ - { - "cve": "CVE-2023-25433", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-120" - ], - "cwe_details": { - "CWE-120": { - "name": "Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')", - "description": "The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow." - } - } - } - ], - "summary": "libtiff 4.5.0 is vulnerable to Buffer Overflow via /libtiff/tools/tiffcrop.c:8499. Incorrect updating of buffer size after rotateImage() in tiffcrop cause heap-buffer-overflow and SEGV.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-523034", - "references": [ - "https://gitlab.com/libtiff/libtiff/-/merge_requests/467", - "https://security-tracker.debian.org/tracker/CVE-2023-25433", - "https://gitlab.com/libtiff/libtiff/-/issues/520", - "https://lists.debian.org/debian-lts-announce/2023/07/msg00034.html" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-6228", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "An issue was found in the tiffcp utility distributed by the libtiff package where a crafted TIFF file on processing may cause a heap-based buffer overflow leads to an application crash.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-539705", - "references": [ - "https://access.redhat.com/errata/RHSA-2024:5079", - "https://access.redhat.com/errata/RHSA-2024:2289", - "https://security-tracker.debian.org/tracker/CVE-2023-6228", - "https://access.redhat.com/security/cve/CVE-2023-6228", - "https://bugzilla.redhat.com/show_bug.cgi?id=2240995" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-52356", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "A segment fault (SEGV) flaw was found in libtiff that could be triggered by passing a crafted tiff file to the TIFFReadRGBATileExt() API. This flaw allows a remote attacker to cause a heap-buffer overflow, leading to a denial of service.", - "severity": "High", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-589395", - "references": [ - "https://access.redhat.com/errata/RHSA-2024:5079", - "https://support.apple.com/kb/HT214123", - "https://support.apple.com/kb/HT214118", - "http://seclists.org/fulldisclosure/2024/Jul/21", - "https://support.apple.com/kb/HT214122", - "https://support.apple.com/kb/HT214117", - "http://seclists.org/fulldisclosure/2024/Jul/20", - "http://seclists.org/fulldisclosure/2024/Jul/23", - "https://support.apple.com/kb/HT214116", - "http://seclists.org/fulldisclosure/2024/Jul/16", - "https://support.apple.com/kb/HT214119", - "https://support.apple.com/kb/HT214124", - "http://seclists.org/fulldisclosure/2024/Jul/17", - "https://support.apple.com/kb/HT214120", - "http://seclists.org/fulldisclosure/2024/Jul/19", - "http://seclists.org/fulldisclosure/2024/Jul/22", - "http://seclists.org/fulldisclosure/2024/Jul/18", - "https://lists.debian.org/debian-lts-announce/2024/03/msg00011.html", - "https://gitlab.com/libtiff/libtiff/-/issues/622", - "https://gitlab.com/libtiff/libtiff/-/merge_requests/546", - "https://security-tracker.debian.org/tracker/CVE-2023-52356", - "https://bugzilla.redhat.com/show_bug.cgi?id=2251344", - "https://access.redhat.com/security/cve/CVE-2023-52356" - ], - "extended_information": { - "short_description": "A heap buffer overflow in libtiff may lead to denial of service when parsing a crafted tiff image.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "To exploit the vulnerability, the attacker must be able to upload a maliciously crafted tiff image which will be parsed by the victim.", - "is_positive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS score does not reflect the contextual prerequisites required to exploit the vulnerability.", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-1916", - "cvss_v3_score": "6.1", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:H", - "cwe": [ - "CWE-125" - ], - "cwe_details": { - "CWE-125": { - "name": "Out-of-bounds Read", - "description": "The product reads data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "7" - } - ] - } - } - } - ], - "summary": "A flaw was found in tiffcrop, a program distributed by the libtiff package. A specially crafted tiff file can lead to an out-of-bounds read in the extractImageSection function in tools/tiffcrop.c, resulting in a denial of service and limited information disclosure. This issue affects libtiff versions 4.x.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-513433", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-1916", - "https://gitlab.com/libtiff/libtiff/-/issues/536", - "https://gitlab.com/libtiff/libtiff/-/issues/537", - "https://gitlab.com/libtiff/libtiff/-/issues/536%2C", - "https://support.apple.com/kb/HT213844" - ] - }, - { - "cves": [ - { - "cve": "CVE-2017-9117", - "cvss_v2_score": "7.5", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-125" - ], - "cwe_details": { - "CWE-125": { - "name": "Out-of-bounds Read", - "description": "The product reads data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "7" - } - ] - } - } - } - ], - "summary": "In LibTIFF 4.0.7, the program processes BMP images without verifying that biWidth and biHeight in the bitmap-information header match the actual input, leading to a heap-based buffer over-read in bmp2tiff.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-54208", - "references": [ - "http://www.securityfocus.com/bid/98581", - "http://bugzilla.maptools.org/show_bug.cgi?id=2690", - "https://security-tracker.debian.org/tracker/CVE-2017-9117", - "https://usn.ubuntu.com/3606-1/" - ] - }, - { - "cves": [ - { - "cve": "CVE-2010-4665", - "cvss_v2_score": "4.3", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:N/A:P", - "cwe": [ - "CWE-189" - ] - } - ], - "summary": "Integer overflow in the ReadDirectory function in tiffdump.c in tiffdump in LibTIFF before 3.9.5 allows remote attackers to cause a denial of service (application crash) or possibly have unspecified other impact via a crafted TIFF file containing a directory data structure with many directory entries.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-36369", - "references": [ - "http://www.securityfocus.com/bid/47338", - "http://lists.fedoraproject.org/pipermail/package-announce/2011-April/058478.html", - "http://www.debian.org/security/2012/dsa-2552", - "http://lists.opensuse.org/opensuse-security-announce/2011-05/msg00005.html", - "https://security-tracker.debian.org/tracker/CVE-2010-4665", - "http://security.gentoo.org/glsa/glsa-201209-02.xml", - "http://secunia.com/advisories/44271", - "http://ubuntu.com/usn/usn-1416-1", - "http://bugzilla.maptools.org/show_bug.cgi?id=2218", - "https://bugzilla.redhat.com/show_bug.cgi?id=695887", - "http://www.remotesensing.org/libtiff/v3.9.5.html", - "http://secunia.com/advisories/50726", - "http://openwall.com/lists/oss-security/2011/04/12/10" - ] - }, - { - "cves": [ - { - "cve": "CVE-2022-1210", - "cvss_v2_score": "4.3", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:N/A:P", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-404" - ], - "cwe_details": { - "CWE-404": { - "name": "Improper Resource Shutdown or Release", - "description": "The product does not release or incorrectly releases a resource before it is made available for re-use." - } - } - } - ], - "summary": "A vulnerability classified as problematic was found in LibTIFF 4.3.0. Affected by this vulnerability is the TIFF File Handler of tiff2ps. Opening a malicious file leads to a denial of service. The attack can be launched remotely but requires user interaction. The exploit has been disclosed to the public and may be used.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-203004", - "references": [ - "https://vuldb.com/?id.196363", - "https://security.netapp.com/advisory/ntap-20220513-0005/", - "https://security-tracker.debian.org/tracker/CVE-2022-1210", - "https://security.gentoo.org/glsa/202210-10", - "https://gitlab.com/libtiff/libtiff/-/issues/402", - "https://gitlab.com/libtiff/libtiff/uploads/c3da94e53cf1e1e8e6d4d3780dc8c42f/example.tiff" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-3576", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-401" - ], - "cwe_details": { - "CWE-401": { - "name": "Missing Release of Memory after Effective Lifetime", - "description": "The product does not sufficiently track and release allocated memory after it has been used, which slowly consumes remaining memory." - } - } - } - ], - "summary": "A memory leak flaw was found in Libtiff's tiffcrop utility. This issue occurs when tiffcrop operates on a TIFF image file, allowing an attacker to pass a crafted TIFF image file to tiffcrop utility, which causes this memory leak issue, resulting an application crash, eventually leading to a denial of service.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-532917", - "references": [ - "https://access.redhat.com/security/cve/CVE-2023-3576", - "https://access.redhat.com/errata/RHSA-2023:6575", - "https://bugzilla.redhat.com/show_bug.cgi?id=2219340", - "https://lists.debian.org/debian-lts-announce/2024/03/msg00011.html", - "https://security-tracker.debian.org/tracker/CVE-2023-3576" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-3164", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "A heap-buffer-overflow vulnerability was found in LibTIFF, in extractImageSection() at tools/tiffcrop.c:7916 and tools/tiffcrop.c:7801. This flaw allows attackers to cause a denial of service via a crafted tiff file.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-521552", - "references": [ - "https://access.redhat.com/security/cve/CVE-2023-3164", - "https://security-tracker.debian.org/tracker/CVE-2023-3164", - "https://gitlab.com/libtiff/libtiff/-/issues/542", - "https://bugzilla.redhat.com/show_bug.cgi?id=2213531" - ], - "extended_information": { - "short_description": "A heap buffer overflow in the tiffcrop utility in libtiff possibly leads to remote code execution when parsing a crafted TIFF file.", - "full_description": "[libTIFF](http://www.simplesystems.org/libtiff/) is a popular library which provides support for the Tag Image File Format (TIFF), a widely used format for storing image data. One of the utilities that can be provided with libtiff is tiffcrop, which is most often used to extract portions of an image for processing.\n\n`tiffcrop` can be run with one or more flags. These flags include, but are not limited to:\n\n* `-S`: With the `-S` flag, `tiffcrop` will divide each image to equal columns and rows.\n* `-R`: With the `-R` flag, the provided TIFF image will be rotated.\n* `-e`: With the `-e` flag, the user can specify the export mode for images and selections from input images.\n\nWhen running `tiffcrop` with the `-e` flag set to `divided`, `multiple` or `separate`, with the `-S` flag and also with the `-R` flag, an attacker can provide a crafted TIFF file which will cause a heap overflow in the `processCropSelections()` function.\n\nAlthough the heap overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "For an attacker to exploit this vulnerability, `tiffcrop` has to be invoked with specific `-e`, '-S' and `-R` flags. In addition to this, the attacker has to be able to supply a crafted TIFF file as input.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "The vulnerability may lead to remote code execution." - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Although heap overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "A crafted TIFF file is publicly available that demonstrates crashing `libtiff`." - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2018-10126", - "cvss_v2_score": "4.3", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:N/A:P", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-476" - ], - "cwe_details": { - "CWE-476": { - "name": "NULL Pointer Dereference", - "description": "A NULL pointer dereference occurs when the application dereferences a pointer that it expects to be valid, but is NULL, typically causing a crash or exit.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "12" - } - ] - } - } - } - ], - "summary": "ijg-libjpeg before 9d, as used in tiff2pdf (from LibTIFF) and other products, does not check for a NULL pointer at a certain place in jpeg_fdct_16x16 in jfdctint.c.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-67637", - "references": [ - "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772%40%3Cdev.mina.apache.org%3E", - "https://security-tracker.debian.org/tracker/CVE-2018-10126", - "https://gitlab.com/libtiff/libtiff/-/issues/128", - "http://bugzilla.maptools.org/show_bug.cgi?id=2786" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-41175", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-190" - ], - "cwe_details": { - "CWE-190": { - "name": "Integer Overflow or Wraparound", - "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "14" - } - ] - } - } - } - ], - "summary": "A vulnerability was found in libtiff due to multiple potential integer overflows in raw2tiff.c. This flaw allows remote attackers to cause a denial of service or possibly execute an arbitrary code via a crafted tiff image, which triggers a heap-based buffer overflow.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-529113", - "references": [ - "https://bugzilla.redhat.com/show_bug.cgi?id=2235264", - "https://access.redhat.com/errata/RHSA-2024:2289", - "https://security-tracker.debian.org/tracker/CVE-2023-41175", - "https://access.redhat.com/security/cve/CVE-2023-41175" - ], - "extended_information": { - "short_description": "An integer overflow in libtiff's raw2tiff may lead to remote code execution when parsing crafted images.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "For an attacker to exploit this vulnerability, `raw2tiff` has to be invoked with the `-l`, `-b` and `-w` flags. In addition to this, the attacker has to be able to supply a crafted TIFF file as input.", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "PoC was published along with the git issue." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "The vulnerability leads to denial of service and possibly remote code execution." - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Although integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2017-5563", - "cvss_v2_score": "6.8", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:P/I:P/A:P", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-125" - ], - "cwe_details": { - "CWE-125": { - "name": "Out-of-bounds Read", - "description": "The product reads data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "7" - } - ] - } - } - } - ], - "summary": "LibTIFF version 4.0.7 is vulnerable to a heap-based buffer over-read in tif_lzw.c resulting in DoS or code execution via a crafted bmp image to tools/bmp2tiff.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-46608", - "references": [ - "https://security.gentoo.org/glsa/201709-27", - "http://bugzilla.maptools.org/show_bug.cgi?id=2664", - "https://usn.ubuntu.com/3606-1/", - "http://www.securityfocus.com/bid/95705", - "https://security-tracker.debian.org/tracker/CVE-2017-5563" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-7006", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-476" - ], - "cwe_details": { - "CWE-476": { - "name": "NULL Pointer Dereference", - "description": "A NULL pointer dereference occurs when the application dereferences a pointer that it expects to be valid, but is NULL, typically causing a crash or exit.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "12" - } - ] - } - } - } - ], - "summary": "A null pointer dereference flaw was found in Libtiff via `tif_dirinfo.c`. This issue may allow an attacker to trigger memory allocation failures through certain means, such as restricting the heap space size or injecting faults, causing a segmentation fault. This can cause an application crash, eventually leading to a denial of service.", - "severity": "High", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-617888", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-7006", - "https://access.redhat.com/security/cve/CVE-2024-7006", - "https://bugzilla.redhat.com/show_bug.cgi?id=2302996", - "https://access.redhat.com/errata/RHSA-2024:6360" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-40745", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-190" - ], - "cwe_details": { - "CWE-190": { - "name": "Integer Overflow or Wraparound", - "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "14" - } - ] - } - } - } - ], - "summary": "LibTIFF is vulnerable to an integer overflow. This flaw allows remote attackers to cause a denial of service (application crash) or possibly execute an arbitrary code via a crafted tiff image, which triggers a heap-based buffer overflow.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libtiff6:4.5.0-6": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libtiff6:4.5.0-6", - "full_path": "libtiff6:4.5.0-6" - } - ] - ] - } - }, - "issue_id": "XRAY-529112", - "references": [ - "https://access.redhat.com/security/cve/CVE-2023-40745", - "https://access.redhat.com/errata/RHSA-2024:2289", - "https://security-tracker.debian.org/tracker/CVE-2023-40745", - "https://security.netapp.com/advisory/ntap-20231110-0005/", - "https://bugzilla.redhat.com/show_bug.cgi?id=2235265" - ], - "extended_information": { - "short_description": "An integer overflow in libtiff’s tiffcp may lead to remote code execution when parsing crafted images.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "For an attacker to exploit this vulnerability, `tiffcp` has to be invoked with the `-m` flag with an attacker-controlled value. In addition to this, the attacker has to be able to supply a crafted TIFF file as input.", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "A PoC which demonstrates denial of service was published along with the git issue." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "The vulnerability leads to denial of service and possibly remote code execution." - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Although integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-2953", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-476" - ], - "cwe_details": { - "CWE-476": { - "name": "NULL Pointer Dereference", - "description": "A NULL pointer dereference occurs when the application dereferences a pointer that it expects to be valid, but is NULL, typically causing a crash or exit.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "12" - } - ] - } - } - } - ], - "summary": "A vulnerability was found in openldap. This security flaw causes a null pointer dereference in ber_memalloc_x() function.", - "severity": "High", - "components": { - "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5", - "full_path": "libldap-2.5-0:2.5.13+dfsg-5" - } - ] - ] - } - }, - "issue_id": "XRAY-520865", - "references": [ - "http://seclists.org/fulldisclosure/2023/Jul/48", - "https://support.apple.com/kb/HT213845", - "http://seclists.org/fulldisclosure/2023/Jul/47", - "https://bugs.openldap.org/show_bug.cgi?id=9904", - "https://security-tracker.debian.org/tracker/CVE-2023-2953", - "https://support.apple.com/kb/HT213844", - "https://access.redhat.com/security/cve/CVE-2023-2953", - "https://security.netapp.com/advisory/ntap-20230703-0005/", - "http://seclists.org/fulldisclosure/2023/Jul/52", - "https://support.apple.com/kb/HT213843" - ] - }, - { - "cves": [ - { - "cve": "CVE-2020-15719", - "cvss_v2_score": "4.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:H/Au:N/C:P/I:P/A:N", - "cvss_v3_score": "4.2", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N", - "cwe": [ - "CWE-295" - ], - "cwe_details": { - "CWE-295": { - "name": "Improper Certificate Validation", - "description": "The product does not validate, or incorrectly validates, a certificate." - } - } - } - ], - "summary": "libldap in certain third-party OpenLDAP packages has a certificate-validation flaw when the third-party package is asserting RFC6125 support. It considers CN even when there is a non-matching subjectAltName (SAN). This is fixed in, for example, openldap-2.4.46-10.el8 in Red Hat Enterprise Linux.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5", - "full_path": "libldap-2.5-0:2.5.13+dfsg-5" - } - ] - ] - } - }, - "issue_id": "XRAY-113528", - "references": [ - "https://kc.mcafee.com/corporate/index?page=content\u0026id=SB10365", - "https://www.oracle.com/security-alerts/cpuapr2022.html", - "http://lists.opensuse.org/opensuse-security-announce/2020-09/msg00033.html", - "https://security-tracker.debian.org/tracker/CVE-2020-15719", - "http://lists.opensuse.org/opensuse-security-announce/2020-09/msg00059.html", - "https://bugzilla.redhat.com/show_bug.cgi?id=1740070", - "https://bugs.openldap.org/show_bug.cgi?id=9266", - "https://access.redhat.com/errata/RHBA-2019:3674" - ] - }, - { - "cves": [ - { - "cve": "CVE-2017-14159", - "cvss_v2_score": "1.9", - "cvss_v2_vector": "CVSS:2.0/AV:L/AC:M/Au:N/C:N/I:N/A:P", - "cvss_v3_score": "4.7", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-665" - ], - "cwe_details": { - "CWE-665": { - "name": "Improper Initialization", - "description": "The product does not initialize or incorrectly initializes a resource, which might leave the resource in an unexpected state when it is accessed or used." - } - } - } - ], - "summary": "slapd in OpenLDAP 2.4.45 and earlier creates a PID file after dropping privileges to a non-root account, which might allow local users to kill arbitrary processes by leveraging access to this non-root account for PID file modification before a root script executes a \"kill `cat /pathname`\" command, as demonstrated by openldap-initscript.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5", - "full_path": "libldap-2.5-0:2.5.13+dfsg-5" - } - ] - ] - } - }, - "issue_id": "XRAY-58392", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2017-14159", - "http://www.openldap.org/its/index.cgi?findid=8703", - "https://www.oracle.com/security-alerts/cpuapr2022.html" - ] - }, - { - "cves": [ - { - "cve": "CVE-2015-3276", - "cvss_v2_score": "5.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:P/A:N", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", - "cwe": [ - "NVD-CWE-noinfo" - ] - } - ], - "summary": "The nss_parse_ciphers function in libraries/libldap/tls_m.c in OpenLDAP does not properly parse OpenSSL-style multi-keyword mode cipher strings, which might cause a weaker than intended cipher to be used and allow remote attackers to have unspecified impact via unknown vectors.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5", - "full_path": "libldap-2.5-0:2.5.13+dfsg-5" - } - ] - ] - } - }, - "issue_id": "XRAY-37126", - "references": [ - "http://rhn.redhat.com/errata/RHSA-2015-2131.html", - "http://www.securitytracker.com/id/1034221", - "https://security-tracker.debian.org/tracker/CVE-2015-3276", - "http://www.oracle.com/technetwork/topics/security/linuxbulletinoct2015-2719645.html", - "https://bugzilla.redhat.com/show_bug.cgi?id=1238322" - ] - }, - { - "cves": [ - { - "cve": "CVE-2017-17740", - "cvss_v2_score": "5.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-119" - ], - "cwe_details": { - "CWE-119": { - "name": "Improper Restriction of Operations within the Bounds of a Memory Buffer", - "description": "The product performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "17" - } - ] - } - } - } - ], - "summary": "contrib/slapd-modules/nops/nops.c in OpenLDAP through 2.4.45, when both the nops module and the memberof overlay are enabled, attempts to free a buffer that was allocated on the stack, which allows remote attackers to cause a denial of service (slapd crash) via a member MODDN operation.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libldap-2.5-0:2.5.13+dfsg-5", - "full_path": "libldap-2.5-0:2.5.13+dfsg-5" - } - ] - ] - } - }, - "issue_id": "XRAY-60510", - "references": [ - "http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00053.html", - "https://security-tracker.debian.org/tracker/CVE-2017-17740", - "http://www.openldap.org/its/index.cgi/Incoming?id=8759", - "https://kc.mcafee.com/corporate/index?page=content\u0026id=SB10365", - "http://lists.opensuse.org/opensuse-security-announce/2019-09/msg00058.html", - "https://www.oracle.com/security-alerts/cpuapr2022.html" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-22365", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "NVD-CWE-noinfo" - ] - } - ], - "summary": "linux-pam (aka Linux PAM) before 1.6.0 allows attackers to cause a denial of service (blocked login process) via mkfifo because the openat call (for protect_dir) lacks O_DIRECTORY.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libpam-modules-bin:1.5.2-6+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libpam-modules-bin:1.5.2-6+deb12u1", - "full_path": "libpam-modules-bin:1.5.2-6+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libpam-modules:1.5.2-6+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libpam-modules:1.5.2-6+deb12u1", - "full_path": "libpam-modules:1.5.2-6+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libpam-runtime:1.5.2-6+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libpam-runtime:1.5.2-6+deb12u1", - "full_path": "libpam-runtime:1.5.2-6+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libpam0g:1.5.2-6+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libpam0g:1.5.2-6+deb12u1", - "full_path": "libpam0g:1.5.2-6+deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-588807", - "references": [ - "https://github.com/linux-pam/linux-pam", - "http://www.openwall.com/lists/oss-security/2024/01/18/3", - "https://github.com/linux-pam/linux-pam/commit/031bb5a5d0d950253b68138b498dc93be69a64cb", - "https://github.com/linux-pam/linux-pam/releases/tag/v1.6.0", - "https://security-tracker.debian.org/tracker/CVE-2024-22365" - ] - }, - { - "cves": [ - { - "cve": "CVE-2015-9019", - "cvss_v2_score": "5.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:N/A:N", - "cvss_v3_score": "5.3", - "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", - "cwe": [ - "CWE-330" - ], - "cwe_details": { - "CWE-330": { - "name": "Use of Insufficiently Random Values", - "description": "The product uses insufficiently random numbers or values in a security context that depends on unpredictable numbers." - } - } - } - ], - "summary": "In libxslt 1.1.29 and earlier, the EXSLT math.random function was not initialized with a random seed during startup, which could cause usage of this function to produce predictable outputs.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libxslt1.1:1.1.35-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libxslt1.1:1.1.35-1", - "full_path": "libxslt1.1:1.1.35-1" - } - ] - ] - } - }, - "issue_id": "XRAY-52917", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2015-9019", - "https://bugzilla.gnome.org/show_bug.cgi?id=758400", - "https://bugzilla.suse.com/show_bug.cgi?id=934119" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-5171", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-190" - ], - "cwe_details": { - "CWE-190": { - "name": "Integer Overflow or Wraparound", - "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "14" - } - ] - } - } - } - ], - "summary": "Integer overflow in libaom internal function img_alloc_helper can lead to heap buffer overflow. This function can be reached via 3 callers:\n\n\n * Calling aom_img_alloc() with a large value of the d_w, d_h, or align parameter may result in integer overflows in the calculations of buffer sizes and offsets and some fields of the returned aom_image_t struct may be invalid.\n * Calling aom_img_wrap() with a large value of the d_w, d_h, or align parameter may result in integer overflows in the calculations of buffer sizes and offsets and some fields of the returned aom_image_t struct may be invalid.\n * Calling aom_img_alloc_with_border() with a large value of the d_w, d_h, align, size_align, or border parameter may result in integer overflows in the calculations of buffer sizes and offsets and some fields of the returned aom_image_t struct may be invalid.", - "severity": "Critical", - "components": { - "deb://debian:bookworm:libaom3:3.6.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libaom3:3.6.0-1", - "full_path": "libaom3:3.6.0-1" - } - ] - ] - } - }, - "issue_id": "XRAY-604193", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-5171", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/6HYUEHZ35ZPY2EONVZCGO6LPT3AMLZCP/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/U5NRNCEYS246CYGOR32MF7OGKWOWER22/", - "https://issues.chromium.org/issues/332382766" - ], - "extended_information": { - "short_description": "An integer overflow in libaom may lead to remote code execution when parsing malicious video data.", - "full_description": "[Libaom](https://aomedia.googlesource.com/aom/) is the reference encoder and decoder library for the `AV1` video codec. AV1 (AOMedia Video 1) is an open, royalty-free video coding format designed for video transmissions over the Internet. It was developed by the Alliance for Open Media (AOMedia), a consortium that includes firms like Google, Cisco, Microsoft, Mozilla, and Netflix.\nThe `aom` in libaom stands for `Alliance for Open Media`, and the library serves as a standard reference codebase that can be used to implement AV1 compression and decompression.\n\nProviding large values as the arguments to the `img_alloc_helper()` function, may lead to an integer overflow and a subsequent heap buffer overflow, which may lead to remote code execution.\n\n`img_alloc_helper()` function is an internal function that is used to allocate memory for an `aom_image_t` structure and its associated image data. This function is very useful when you need to manually create an image buffer that can then be used with the AOM codec for various operations like encoding or decoding.\n\nThe vulnerability cannot be exploited directly by calling `img_alloc_helper()` because it is an internal function. \n\nAlthough integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.\n\nTo exploit this vulnerability the following functions can be called with excessively large values as parameters:\n\n* `aom_img_alloc()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_wrap()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_alloc_with_border()` with a large value of the d_w, d_h, align, size_align, or border parameters.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "The published exploit demonstrates DoS." - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Although integer overflow could potentially lead to RCE, no exploit or technical writeup suggested such an impact for this issue.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "The highest potential impact of this issue is severe (Remote Code Execution). Although no such impact has been demonstrated in practice." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "An attacker would need to find input propagating into the libaom encoding or decoding operations.", - "is_positive": true - } - ], - "remediation": "##### Development mitigations\n\nMake sure the following functions don't accept excessively large values as arguments to the following functions:\n\n* `aom_img_alloc()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_wrap()` with a large value of the d_w, d_h, or align parameters.\n\n* `aom_img_alloc_with_border()` with a large value of the d_w, d_h, align, size_align, or border parameters." - } - }, - { - "cves": [ - { - "cve": "CVE-2023-39616", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-119" - ], - "cwe_details": { - "CWE-119": { - "name": "Improper Restriction of Operations within the Bounds of a Memory Buffer", - "description": "The product performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "17" - } - ] - } - } - } - ], - "summary": "AOMedia v3.0.0 to v3.5.0 was discovered to contain an invalid read memory access via the component assign_frame_buffer_p in av1/common/av1_common_int.h.", - "severity": "High", - "components": { - "deb://debian:bookworm:libaom3:3.6.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libaom3:3.6.0-1", - "full_path": "libaom3:3.6.0-1" - } - ] - ] - } - }, - "issue_id": "XRAY-529506", - "references": [ - "https://bugs.chromium.org/p/aomedia/issues/detail?id=3372#c3", - "https://security-tracker.debian.org/tracker/CVE-2023-39616" - ], - "extended_information": { - "short_description": "Invalid pointer dereference in libaom leads to denial of service when encoding crafted video data with nondefault configuration options set.", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "The published exploit demonstrates DoS" - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The issue can be exploited by the `aomenc` CLI tool when called on arbitrary input file with the flag `--drop-frame=1` - \n`aomenc --passes=1 -h 1 -w 1 --drop-frame=1 --end-usage=cbr --buf-sz=1 -o /dev/null poc`\n \n\nAlternatively, the issue can be exploited through `libaom` when calling `aom_codec_enc_init` where the 3rd arg (`config`) has `dropframe_thresh == 1` + calling `aom_codec_encode` with external input to the 2nd arg (`img`)", - "is_positive": true - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "Exploiting the DoS via invocation of the `aomenc` CLI tool has minimal security impact, since exploitation will cause the `aomenc` forked utiliy process to crash (crashing a forked process has minimal security impact)\n\nThe issue can also be exploited via specific calls to `libaom`, however the configuration needed is extremely rare and crashing a video encoder usually does not have a high security impact.\n\nDebian classified this CVE as a \"minor issue\"", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-6879", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "Increasing the resolution of video frames, while performing a multi-threaded encode, can result in a heap overflow in av1_loop_restoration_dealloc().", - "severity": "Critical", - "components": { - "deb://debian:bookworm:libaom3:3.6.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libaom3:3.6.0-1", - "full_path": "libaom3:3.6.0-1" - } - ] - ] - } - }, - "issue_id": "XRAY-585747", - "references": [ - "https://aomedia.googlesource.com/aom/+/refs/tags/v3.7.1", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D6C2HN4T2S6GYNTAUXLH45LQZHK7QPHP/", - "https://crbug.com/aomedia/3491", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/AYONA2XSNFMXLAW4IHLFI5UVV3QRNG5K/", - "https://security-tracker.debian.org/tracker/CVE-2023-6879" - ], - "extended_information": { - "short_description": "Heap buffer overread in the av1 module of the aom library can lead to denial of service when resizing frames under special conditions.", - "full_description": "AOM (Alliance for Open Media) is an open-source, royalty-free video codec library implemented in C, developed by the Alliance for Open Media, a consortium of technology companies and research institutions. The AOM library supports the AV1, VP9, and Thor video formats, providing high-quality video compression and is used for a variety of applications, including video streaming, video conferencing, and video editing.\nThe AV1 codec, developed by the Alliance for Open Media, is a state-of-the-art video compression technology that achieves exceptional efficiency while preserving high visual quality. The AOM library provides a comprehensive toolkit for working with AV1-encoded video streams, offering encoding, decoding, and manipulation capabilities.\n\nA vulnerability was found when using the `aom_codec_destroy()` function to clean up memory after resizing AV1 frames, specifically when:\n\n- Using AV1 codec (`aom_codec_av1_cx()`)\n- Utilizing multiple threads\n```\naom_codec_enc_cfg_t cfg;\naom_codec_enc_config_default(iface, \u0026cfg, AOM_USAGE_GOOD_QUALITY));\ncfg.g_threads = 4;\n```\n\nUnder these conditions, a Denial of Service (DoS) vulnerability emerges, manifesting as a heap buffer overread during object destruction.", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "A public example of vulnerable AOM code exists, which shows how a DoS might be triggered." - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "Under normal circumstances, the attacker cannot supply input which will trigger this vulnerability (either the vulnerable code exists or does not exist).", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The vulnerability triggers under the following conditions -\n- use of the AV1 codec (`aom_codec_av1_cx()`)\n- use of more than 1 thread:\n```\naom_codec_enc_cfg_t cfg;\naom_codec_enc_config_default(iface, \u0026cfg, AOM_USAGE_GOOD_QUALITY));\ncfg.g_threads = 4;\n```\n- cleaning the memory at the end of the encoding process (`aom_codec_destroy()`)", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2024-28757" - } - ], - "summary": "libexpat through 2.6.1 allows an XML Entity Expansion attack when there is isolated use of external parsers (created via XML_ExternalEntityParserCreate).", - "severity": "Low", - "components": { - "deb://debian:bookworm:libexpat1:2.5.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", - "full_path": "libexpat1:2.5.0-1" - } - ] - ] - } - }, - "issue_id": "XRAY-593447", - "references": [ - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LKJ7V5F6LJCEQJXDBWGT27J7NAP3E3N7/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/VK2O34GH43NTHBZBN7G5Y6YKJKPUCTBE/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/FPLC6WDSRDUYS7F7JWAOVOHFNOUQ43DD/", - "http://www.openwall.com/lists/oss-security/2024/03/15/1", - "https://github.com/libexpat/libexpat/issues/839", - "https://github.com/libexpat/libexpat/pull/842", - "https://security.netapp.com/advisory/ntap-20240322-0001/", - "https://security-tracker.debian.org/tracker/CVE-2024-28757" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-45492", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-190" - ], - "cwe_details": { - "CWE-190": { - "name": "Integer Overflow or Wraparound", - "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "14" - } - ] - } - } - } - ], - "summary": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", - "severity": "Critical", - "components": { - "deb://debian:bookworm:libexpat1:2.5.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", - "full_path": "libexpat1:2.5.0-1" - } - ] - ] - } - }, - "issue_id": "XRAY-632612", - "references": [ - "https://github.com/libexpat/libexpat/issues/889", - "https://security-tracker.debian.org/tracker/CVE-2024-45492", - "https://github.com/libexpat/libexpat/pull/892" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-52426", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-776" - ], - "cwe_details": { - "CWE-776": { - "name": "Improper Restriction of Recursive Entity References in DTDs ('XML Entity Expansion')", - "description": "The product uses XML documents and allows their structure to be defined with a Document Type Definition (DTD), but it does not properly control the number of recursive definitions of entities." - } - } - } - ], - "summary": "libexpat through 2.5.0 allows recursive XML Entity Expansion if XML_DTD is undefined at compile time.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libexpat1:2.5.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", - "full_path": "libexpat1:2.5.0-1" - } - ] - ] - } - }, - "issue_id": "XRAY-589896", - "references": [ - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/PNRIHC7DVVRAIWFRGV23Y6UZXFBXSQDB/", - "https://security-tracker.debian.org/tracker/CVE-2023-52426", - "https://cwe.mitre.org/data/definitions/776.html", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/WNUBSGZFEZOBHJFTAD42SAN4ATW2VEMV/", - "https://security.netapp.com/advisory/ntap-20240307-0005/", - "https://github.com/libexpat/libexpat/commit/0f075ec8ecb5e43f8fdca5182f8cca4703da0404", - "https://github.com/libexpat/libexpat/pull/777" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-45491", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-190" - ], - "cwe_details": { - "CWE-190": { - "name": "Integer Overflow or Wraparound", - "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "14" - } - ] - } - } - } - ], - "summary": "An issue was discovered in libexpat before 2.6.3. dtdCopy in xmlparse.c can have an integer overflow for nDefaultAtts on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", - "severity": "Critical", - "components": { - "deb://debian:bookworm:libexpat1:2.5.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", - "full_path": "libexpat1:2.5.0-1" - } - ] - ] - } - }, - "issue_id": "XRAY-632611", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-45491", - "https://github.com/libexpat/libexpat/pull/891", - "https://github.com/libexpat/libexpat/issues/888" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-45490", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-611" - ], - "cwe_details": { - "CWE-611": { - "name": "Improper Restriction of XML External Entity Reference", - "description": "The product processes an XML document that can contain XML entities with URIs that resolve to documents outside of the intended sphere of control, causing the product to embed incorrect documents into its output." - } - } - } - ], - "summary": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", - "severity": "Critical", - "components": { - "deb://debian:bookworm:libexpat1:2.5.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", - "full_path": "libexpat1:2.5.0-1" - } - ] - ] - } - }, - "issue_id": "XRAY-632613", - "references": [ - "https://github.com/libexpat/libexpat/issues/887", - "https://security-tracker.debian.org/tracker/CVE-2024-45490", - "https://github.com/libexpat/libexpat/pull/890" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-52425", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-400" - ], - "cwe_details": { - "CWE-400": { - "name": "Uncontrolled Resource Consumption", - "description": "The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources." - } - } - } - ], - "summary": "libexpat through 2.5.0 allows a denial of service (resource consumption) because many full reparsings are required in the case of a large token for which multiple buffer fills are needed.", - "severity": "High", - "components": { - "deb://debian:bookworm:libexpat1:2.5.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", - "full_path": "libexpat1:2.5.0-1" - } - ] - ] - } - }, - "issue_id": "XRAY-589898", - "references": [ - "http://www.openwall.com/lists/oss-security/2024/03/20/5", - "https://security.netapp.com/advisory/ntap-20240614-0003/", - "https://github.com/libexpat/libexpat/pull/789", - "https://lists.debian.org/debian-lts-announce/2024/04/msg00006.html", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/PNRIHC7DVVRAIWFRGV23Y6UZXFBXSQDB/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/WNUBSGZFEZOBHJFTAD42SAN4ATW2VEMV/", - "https://security-tracker.debian.org/tracker/CVE-2023-52425" - ], - "extended_information": { - "short_description": "A design problem in libexpat may lead to denial of service when parsing a crafted XML document with large tokens.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "A PoC demonstrating denial-of-service can be found in Expat's tests." - }, - { - "name": "The issue is trivial to exploit and does not require a published writeup or PoC", - "description": "The issue doesn't require any in-depth knowledge to trigger as a proof-of-concept exists in the official fix commit." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Exploitation of the vulnerability leads to high resource consumption which may lead to denial of service." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "Exploitation requires passing user-controlled input to an XML parsing function such as `XML_Parse`.", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2013-0337", - "cvss_v2_score": "7.5", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P", - "cwe": [ - "CWE-264" - ] - } - ], - "summary": "The default configuration of nginx, possibly 1.3.13 and earlier, uses world-readable permissions for the (1) access.log and (2) error.log files, which allows local users to obtain sensitive information by reading the files.", - "severity": "Low", - "components": { - "deb://debian:bookworm:nginx:1.25.2-1~bookworm": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:nginx:1.25.2-1~bookworm", - "full_path": "nginx:1.25.2-1~bookworm" - } - ] - ] - } - }, - "issue_id": "XRAY-32935", - "references": [ - "http://security.gentoo.org/glsa/glsa-201310-04.xml", - "http://www.openwall.com/lists/oss-security/2013/02/24/1", - "http://secunia.com/advisories/55181", - "http://www.openwall.com/lists/oss-security/2013/02/22/1", - "https://security-tracker.debian.org/tracker/CVE-2013-0337", - "http://www.openwall.com/lists/oss-security/2013/02/21/15" - ] - }, - { - "cves": [ - { - "cve": "CVE-2009-4487", - "cvss_v2_score": "6.8", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:P/I:P/A:P", - "cwe": [ - "NVD-CWE-noinfo" - ] - } - ], - "summary": "nginx 0.7.64 writes data to a log file without sanitizing non-printable characters, which might allow remote attackers to modify a window's title, or possibly execute arbitrary commands or overwrite files, via an HTTP request containing an escape sequence for a terminal emulator.", - "severity": "Low", - "components": { - "deb://debian:bookworm:nginx:1.25.2-1~bookworm": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:nginx:1.25.2-1~bookworm", - "full_path": "nginx:1.25.2-1~bookworm" - } - ] - ] - } - }, - "issue_id": "XRAY-34279", - "references": [ - "http://www.securityfocus.com/bid/37711", - "http://www.ush.it/team/ush/hack_httpd_escape/adv.txt", - "https://security-tracker.debian.org/tracker/CVE-2009-4487", - "http://www.securityfocus.com/archive/1/508830/100/0/threaded" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-7347", - "cvss_v3_score": "4.7", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-125" - ], - "cwe_details": { - "CWE-125": { - "name": "Out-of-bounds Read", - "description": "The product reads data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "7" - } - ] - } - } - } - ], - "summary": "NGINX Open Source and NGINX Plus have a vulnerability in the ngx_http_mp4_module, which might allow an attacker to over-read NGINX worker memory resulting in its termination, using a specially crafted mp4 file. The issue only affects NGINX if it is built with the ngx_http_mp4_module and the mp4 directive is used in the configuration file. Additionally, the attack is possible only if an attacker can trigger the processing of a specially crafted mp4 file with the ngx_http_mp4_module.  Note: Software versions which have reached End of Technical Support (EoTS) are not evaluated.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:nginx:1.25.2-1~bookworm": { - "fixed_versions": [ - "[1.26.0-2]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:nginx:1.25.2-1~bookworm", - "full_path": "nginx:1.25.2-1~bookworm" - } - ] - ] - } - }, - "issue_id": "XRAY-619023", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-7347", - "https://my.f5.com/manage/s/article/K000140529" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-1580" - } - ], - "summary": "An integer overflow in dav1d AV1 decoder that can occur when decoding videos with large frame size. This can lead to memory corruption within the AV1 decoder. We recommend upgrading past version 1.4.0 of dav1d.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libdav1d6:1.0.0-2": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libdav1d6:1.0.0-2", - "full_path": "libdav1d6:1.0.0-2" - } - ] - ] - } - }, - "issue_id": "XRAY-590844", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-1580", - "http://seclists.org/fulldisclosure/2024/Mar/38", - "https://support.apple.com/kb/HT214093", - "https://code.videolan.org/videolan/dav1d/-/releases/1.4.0", - "http://seclists.org/fulldisclosure/2024/Mar/41", - "http://seclists.org/fulldisclosure/2024/Mar/39", - "https://support.apple.com/kb/HT214098", - "http://seclists.org/fulldisclosure/2024/Mar/40", - "http://seclists.org/fulldisclosure/2024/Mar/36", - "https://support.apple.com/kb/HT214096", - "https://support.apple.com/kb/HT214095", - "http://seclists.org/fulldisclosure/2024/Mar/37", - "https://support.apple.com/kb/HT214097", - "https://support.apple.com/kb/HT214094", - "https://code.videolan.org/videolan/dav1d/-/blob/master/NEWS", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/5EPMUNDMEBGESOJ2ZNCWYEAYOOEKNWOO/" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-32570", - "cvss_v3_score": "5.9", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-362" - ], - "cwe_details": { - "CWE-362": { - "name": "Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')", - "description": "The product contains a code sequence that can run concurrently with other code, and the code sequence requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence that is operating concurrently.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "21" - } - ] - } - } - } - ], - "summary": "VideoLAN dav1d before 1.2.0 has a thread_task.c race condition that can lead to an application crash, related to dav1d_decode_frame_exit.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libdav1d6:1.0.0-2": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libdav1d6:1.0.0-2", - "full_path": "libdav1d6:1.0.0-2" - } - ] - ] - } - }, - "issue_id": "XRAY-519404", - "references": [ - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/3WGSO7UMOF4MVLQ5H6KIV7OG6ONS377B/", - "https://security-tracker.debian.org/tracker/CVE-2023-32570", - "https://code.videolan.org/videolan/dav1d/-/tags/1.2.0", - "https://code.videolan.org/videolan/dav1d/-/commit/cf617fdae0b9bfabd27282854c8e81450d955efa", - "https://security.gentoo.org/glsa/202310-05", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LXZ6CUNJFDJLCFOZHY2TIGMCAEITLCRP/" - ] - }, - { - "cves": [ - { - "cve": "CVE-2016-2781", - "cvss_v2_score": "2.1", - "cvss_v2_vector": "CVSS:2.0/AV:L/AC:L/Au:N/C:N/I:P/A:N", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N", - "cwe": [ - "CWE-20" - ], - "cwe_details": { - "CWE-20": { - "name": "Improper Input Validation", - "description": "The product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "6" - } - ] - } - } - } - ], - "summary": "chroot in GNU coreutils, when used with --userspec, allows local users to escape to the parent session via a crafted TIOCSTI ioctl call, which pushes characters to the terminal's input buffer.", - "severity": "Low", - "components": { - "deb://debian:bookworm:coreutils:9.1-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:coreutils:9.1-1", - "full_path": "coreutils:9.1-1" - } - ] - ] - } - }, - "issue_id": "XRAY-28549", - "references": [ - "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772%40%3Cdev.mina.apache.org%3E", - "https://security-tracker.debian.org/tracker/CVE-2016-2781", - "http://www.openwall.com/lists/oss-security/2016/02/28/2", - "http://www.openwall.com/lists/oss-security/2016/02/28/3" - ] - }, - { - "cves": [ - { - "cve": "CVE-2017-18018", - "cvss_v2_score": "1.9", - "cvss_v2_vector": "CVSS:2.0/AV:L/AC:M/Au:N/C:N/I:P/A:N", - "cvss_v3_score": "4.7", - "cvss_v3_vector": "CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:N", - "cwe": [ - "CWE-362" - ], - "cwe_details": { - "CWE-362": { - "name": "Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')", - "description": "The product contains a code sequence that can run concurrently with other code, and the code sequence requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence that is operating concurrently.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "21" - } - ] - } - } - } - ], - "summary": "In GNU Coreutils through 8.29, chown-core.c in chown and chgrp does not prevent replacement of a plain file with a symlink during use of the POSIX \"-R -L\" options, which allows local users to modify the ownership of arbitrary files by leveraging a race condition.", - "severity": "Low", - "components": { - "deb://debian:bookworm:coreutils:9.1-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:coreutils:9.1-1", - "full_path": "coreutils:9.1-1" - } - ] - ] - } - }, - "issue_id": "XRAY-60415", - "references": [ - "http://lists.gnu.org/archive/html/coreutils/2017-12/msg00045.html", - "https://security-tracker.debian.org/tracker/CVE-2017-18018" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-28085" - } - ], - "summary": "wall in util-linux through 2.40, often installed with setgid tty permissions, allows escape sequences to be sent to other users' terminals through argv. (Specifically, escape sequences received from stdin are blocked, but escape sequences received from argv are not blocked.) There may be plausible scenarios where this leads to account takeover.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:bsdutils:1:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:bsdutils:1:2.38.1-5+b1", - "full_path": "bsdutils:1:2.38.1-5+b1" - } - ] - ] - }, - "deb://debian:bookworm:libblkid1:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libblkid1:2.38.1-5+b1", - "full_path": "libblkid1:2.38.1-5+b1" - } - ] - ] - }, - "deb://debian:bookworm:libmount1:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libmount1:2.38.1-5+b1", - "full_path": "libmount1:2.38.1-5+b1" - } - ] - ] - }, - "deb://debian:bookworm:libsmartcols1:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libsmartcols1:2.38.1-5+b1", - "full_path": "libsmartcols1:2.38.1-5+b1" - } - ] - ] - }, - "deb://debian:bookworm:libuuid1:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libuuid1:2.38.1-5+b1", - "full_path": "libuuid1:2.38.1-5+b1" - } - ] - ] - }, - "deb://debian:bookworm:mount:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:mount:2.38.1-5+b1", - "full_path": "mount:2.38.1-5+b1" - } - ] - ] - }, - "deb://debian:bookworm:util-linux-extra:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:util-linux-extra:2.38.1-5+b1", - "full_path": "util-linux-extra:2.38.1-5+b1" - } - ] - ] - }, - "deb://debian:bookworm:util-linux:2.38.1-5+b1": { - "fixed_versions": [ - "[2.38.1-5+deb12u1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:util-linux:2.38.1-5+b1", - "full_path": "util-linux:2.38.1-5+b1" - } - ] - ] - } - }, - "issue_id": "XRAY-596193", - "references": [ - "http://www.openwall.com/lists/oss-security/2024/03/27/8", - "http://www.openwall.com/lists/oss-security/2024/03/28/2", - "http://www.openwall.com/lists/oss-security/2024/03/27/9", - "http://www.openwall.com/lists/oss-security/2024/03/28/3", - "https://lists.debian.org/debian-lts-announce/2024/04/msg00005.html", - "https://www.openwall.com/lists/oss-security/2024/03/27/5", - "https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/", - "https://security.netapp.com/advisory/ntap-20240531-0003/", - "https://github.com/util-linux/util-linux/security/advisories/GHSA-xv2h-c6ww-mrjq", - "https://security-tracker.debian.org/tracker/CVE-2024-28085", - "http://www.openwall.com/lists/oss-security/2024/03/27/5", - "http://www.openwall.com/lists/oss-security/2024/03/28/1", - "https://github.com/skyler-ferrante/CVE-2024-28085", - "https://people.rit.edu/sjf5462/6831711781/wall_2_27_2024.txt", - "http://www.openwall.com/lists/oss-security/2024/03/27/7", - "http://www.openwall.com/lists/oss-security/2024/03/27/6" - ], - "extended_information": { - "short_description": "Escape character injection in util-linux wall may allow for data leakage by local attackers in specific scenarios", - "full_description": "[util-linux](https://github.com/util-linux/util-linux) is a random collection of Linux utilities. \nwall (write all) allows a user to send a text message to all other users (terminals) in the system.\nIt was discovered that wall does not filter escape sequences from command line arguments, allowing a local user to inject escape characters into other users' terminals.\n\nThis vulnerability can be used in a per-target social engineering attack, where the local attacker injects seemingly innocent text to other users' terminals, making them write sensitive information (ex. their password) which can subsequently be leaked to local files, depending on the exact scenario.\n\nWhile an example PoC demonstrated the possibility to leak user passwords when the victim uses `sudo`, in reality exploitation of this issue requires the attacker to deeply research the affected system and requires the victim's interaction, making it difficult to exploit even in low volumes.", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The `wall` executable must have `setgid` permissions in order to be vulnerable. In addition, the victim's terminal must accept messages from other terminals (controlled via the `mesg` utility).", - "is_positive": true - }, - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "description": "The injected escape characters may allow the local attacker to social engineer a victim on the same machine. The impact of exploiting the vulnerability depends on what actions are performed by the victim user, but in most cases will lead to local privilege escalation of the attacker.", - "is_positive": true - }, - { - "name": "Exploiting the issue requires the user to interact with the vulnerable software", - "description": "The victim must interact with the injected escape characters in some way to cause code execution or data leakage. The injected escape characters cannot cause any harm on their own, only assist the attacker with social engineering.", - "is_positive": true - }, - { - "name": "The issue is trivial to exploit and does not require a published writeup or PoC", - "description": "A local attacker can simply call `exec` with `wall`, supplying escape characters in `argv` -\n```c\nexecve(\"/usr/bin/wall\", argv, envp);\n```" - } - ], - "remediation": "##### Deployment mitigations\n\nDisable write access of other users to your terminal -\n```bash\nmesg n\n```\n\n##### Deployment mitigations\n\nRemove the setgid permissions from wall -\n```bash\nsudo chmod g-s `which wall`\n```" - } - }, - { - "cves": [ - { - "cve": "CVE-2022-0563", - "cvss_v2_score": "1.9", - "cvss_v2_vector": "CVSS:2.0/AV:L/AC:M/Au:N/C:P/I:N/A:N", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", - "cwe": [ - "CWE-209" - ], - "cwe_details": { - "CWE-209": { - "name": "Generation of Error Message Containing Sensitive Information", - "description": "The product generates an error message that includes sensitive information about its environment, users, or associated data." - } - } - } - ], - "summary": "A flaw was found in the util-linux chfn and chsh utilities when compiled with Readline support. The Readline library uses an \"INPUTRC\" environment variable to get a path to the library config file. When the library cannot parse the specified file, it prints an error message containing data from the file. This flaw allows an unprivileged user to read root-owned files, potentially leading to privilege escalation. This flaw affects util-linux versions prior to 2.37.4.", - "severity": "Low", - "components": { - "deb://debian:bookworm:bsdutils:1:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:bsdutils:1:2.38.1-5+b1", - "full_path": "bsdutils:1:2.38.1-5+b1" - } - ] - ] - }, - "deb://debian:bookworm:libblkid1:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libblkid1:2.38.1-5+b1", - "full_path": "libblkid1:2.38.1-5+b1" - } - ] - ] - }, - "deb://debian:bookworm:libmount1:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libmount1:2.38.1-5+b1", - "full_path": "libmount1:2.38.1-5+b1" - } - ] - ] - }, - "deb://debian:bookworm:libsmartcols1:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libsmartcols1:2.38.1-5+b1", - "full_path": "libsmartcols1:2.38.1-5+b1" - } - ] - ] - }, - "deb://debian:bookworm:libuuid1:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libuuid1:2.38.1-5+b1", - "full_path": "libuuid1:2.38.1-5+b1" - } - ] - ] - }, - "deb://debian:bookworm:mount:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:mount:2.38.1-5+b1", - "full_path": "mount:2.38.1-5+b1" - } - ] - ] - }, - "deb://debian:bookworm:util-linux-extra:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:util-linux-extra:2.38.1-5+b1", - "full_path": "util-linux-extra:2.38.1-5+b1" - } - ] - ] - }, - "deb://debian:bookworm:util-linux:2.38.1-5+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:util-linux:2.38.1-5+b1", - "full_path": "util-linux:2.38.1-5+b1" - } - ] - ] - } - }, - "issue_id": "XRAY-198072", - "references": [ - "https://lore.kernel.org/util-linux/20220214110609.msiwlm457ngoic6w%40ws.net.home/T/#u", - "https://security.netapp.com/advisory/ntap-20220331-0002/", - "https://security-tracker.debian.org/tracker/CVE-2022-0563", - "https://security.gentoo.org/glsa/202401-08" - ], - "extended_information": { - "short_description": "Improper file-read in util-linux chsh and chfn tools can lead to sensitive data leakage when an attacker controls the INPUTRC environment variable.", - "full_description": "[util-linux](https://github.com/util-linux/util-linux) is a random collection of Linux utilities.\n`chsh` is used to change the login shell. `chfn` is used to change finger information.\n\nThe [GNU Readline library](https://tiswww.case.edu/php/chet/readline/rltop.html) provides a set of functions for use by applications that allow users to edit command lines as they are typed in. The Readline library is loads a library configuration file, passed via the `INPUTRC` environment variable.\n\nWhen the `chsh` and `chfn` are compiled with the `readline` library, and the `INPUTRC` environment variable is defined to a non-valid library config file, it will print an error message and leak some data from the malformed config file. \n\nThe major Linux distributions: Alpine, Debian and Ubuntu don’t use the `util-linux` package to compile `chsh` and `chfn` - instead they use the `shadow` package which isn’t vulnerable to this issue.\n\nAlso, Red Hat compiles `util-linux` without linking the vulnerable `readline` library.\n\nSince both of these tools have root-`setuid` permissions by default, a local attacker can in theory leak partial data from arbitrary (root-owned) files in the system by running them with an arbitrary `INPUTRC` environment variable.\n\nBut, when manually compiling `util-linux` from a vulnerable source, and installing this version on the system, the utilities lose their `setuid` flag. This is a feature of Linux systems that removes the `setuid` after a file has been modified. It must be manually enabled again using `chmod u+s` to read root-owned files.", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "The issue can only be exploited by an attacker that can execute code on the vulnerable machine (excluding exceedingly rare circumstances)", - "is_positive": true - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "All the major Linux distributions don’t use a vulnerable version of the tools. Also, when manually compiling the tools from the source, the `setuid` flag is removed from the tools, thus losing access to leak the contents from root-owned files.", - "is_positive": true - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "Partial file data leakage", - "is_positive": true - }, - { - "name": "The issue is trivial to exploit and does not require a published writeup or PoC", - "description": "A local attacker may set the `INPUTRC` environment variable to an arbitrary file that should be leaked" - } - ], - "remediation": "##### Deployment mitigations\n\nIf a vulnerable version of `util-linux` was compiled manually, remove the SUID bit from the `chsh` and `chfn` tools using the `chmod u-s` command on them." - } - }, - { - "cves": [ - { - "cve": "CVE-2022-3219", - "cvss_v3_score": "3.3", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "GnuPG can be made to spin on a relatively small input by (for example) crafting a public key with thousands of signatures attached, compressed down to just a few KB.", - "severity": "Low", - "components": { - "deb://debian:bookworm:gpgv:2.2.40-1.1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:gpgv:2.2.40-1.1", - "full_path": "gpgv:2.2.40-1.1" - } - ] - ] - } - }, - "issue_id": "XRAY-425648", - "references": [ - "https://marc.info/?l=oss-security\u0026m=165696590211434\u0026w=4", - "https://security-tracker.debian.org/tracker/CVE-2022-3219", - "https://dev.gnupg.org/D556", - "https://security.netapp.com/advisory/ntap-20230324-0001/", - "https://bugzilla.redhat.com/show_bug.cgi?id=2127010", - "https://dev.gnupg.org/T5993", - "https://access.redhat.com/security/cve/CVE-2022-3219" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-39804" - } - ], - "summary": "In GNU tar before 1.35, mishandled extension attributes in a PAX archive can lead to an application crash in xheader.c.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:tar:1.34+dfsg-1.2": { - "fixed_versions": [ - "[1.34+dfsg-1.2+deb12u1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:tar:1.34+dfsg-1.2", - "full_path": "tar:1.34+dfsg-1.2" - } - ] - ] - } - }, - "issue_id": "XRAY-540509", - "references": [ - "https://git.savannah.gnu.org/cgit/tar.git/commit/?id=a339f05cd269013fa133d2f148d73f6f7d4247e4", - "https://git.savannah.gnu.org/cgit/tar.git/tree/src/xheader.c?h=release_1_34#n1723", - "https://security-tracker.debian.org/tracker/CVE-2023-39804", - "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1058079" - ] - }, - { - "cves": [ - { - "cve": "CVE-2005-2541", - "cvss_v2_score": "10.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:C/I:C/A:C", - "cwe": [ - "NVD-CWE-Other" - ] - } - ], - "summary": "Tar 1.15.1 does not properly warn the user when extracting setuid or setgid files, which may allow local users or remote attackers to gain privileges.", - "severity": "Low", - "components": { - "deb://debian:bookworm:tar:1.34+dfsg-1.2": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:tar:1.34+dfsg-1.2", - "full_path": "tar:1.34+dfsg-1.2" - } - ] - ] - } - }, - "issue_id": "XRAY-28223", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2005-2541", - "https://lists.apache.org/thread.html/rc713534b10f9daeee2e0990239fa407e2118e4aa9e88a7041177497c%40%3Cissues.guacamole.apache.org%3E", - "http://marc.info/?l=bugtraq\u0026m=112327628230258\u0026w=2" - ], - "extended_information": { - "short_description": "Preserving SETUID/SETGID bits when extracting with tar may lead to privilege escalation.", - "full_description": "When running as the \"root\" user, tar will restore by default the original permissions to any extracted files (this can be controlled via the `-p` argument). One of the restored permission bits are the SETUID/SETGID bits which make the extracted executable automatically elevate to \"root\" privileges, regardless of the user that ran the executable.\n\nThis behavior could be an issue when the root user extracts a crafted tar archive, which contains a SUID-enabled malicious executable, that allows privilege escalation.\nDe-facto, this behavior is widely known, documented and accepted behavior, and as such this issue did not receive a fix.", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "Exploiting the issue requires the user to interact with the vulnerable software", - "description": "A root user must extract the \"affected\" tar archive", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker must find a vulnerability in the extracted SETUID program in order to run arbitrary code, or alternatively make the root user extract an attacker-crafted tar archive", - "is_positive": true - }, - { - "name": "The issue cannot be exploited on its own, and can only be used as part of an attack chain", - "description": "Simply preserving the SETUID/SETGID bits will not lead to privilege escalation. The extracted program must still have a vulnerability that will allow the unprivileged user to achieve arbitrary (local) code execution", - "is_positive": true - }, - { - "name": "The issue has been disputed by the vendor", - "description": "Both Red Hat and Debian security trackers disputed the issue, citing \"This is the documented and expected behaviour of tar.\"", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2022-48303", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-125" - ], - "cwe_details": { - "CWE-125": { - "name": "Out-of-bounds Read", - "description": "The product reads data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "7" - } - ] - } - } - } - ], - "summary": "GNU Tar through 1.34 has a one-byte out-of-bounds read that results in use of uninitialized memory for a conditional jump. Exploitation to change the flow of control has not been demonstrated. The issue occurs in from_header in list.c via a V7 archive in which mtime has approximately 11 whitespace characters.", - "severity": "Low", - "components": { - "deb://debian:bookworm:tar:1.34+dfsg-1.2": { - "fixed_versions": [ - "[1.34+dfsg-1.2+deb12u1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:tar:1.34+dfsg-1.2", - "full_path": "tar:1.34+dfsg-1.2" - } - ] - ] - } - }, - "issue_id": "XRAY-414652", - "references": [ - "https://savannah.gnu.org/bugs/?62387", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/CRY7VEL4AIG3GLIEVCTOXRZNSVYDYYUD/", - "https://security-tracker.debian.org/tracker/CVE-2022-48303", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/X5VQYCO52Z7GAVCLRYUITN7KXHLRZQS4/", - "https://savannah.gnu.org/patch/?10307" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-25062", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-416" - ], - "cwe_details": { - "CWE-416": { - "name": "Use After Free", - "description": "Referencing memory after it has been freed can cause a program to crash, use unexpected values, or execute code.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "4" - } - ] - } - } - } - ], - "summary": "An issue was discovered in libxml2 before 2.11.7 and 2.12.x before 2.12.5. When using the XML Reader interface with DTD validation and XInclude expansion enabled, processing crafted XML documents can lead to an xmlValidatePopElement use-after-free.", - "severity": "High", - "components": { - "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1": { - "fixed_versions": [ - "[2.12.7+dfsg-1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1", - "full_path": "libxml2:2.9.14+dfsg-1.3~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-589897", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-25062", - "https://gitlab.gnome.org/GNOME/libxml2/-/tags", - "https://gitlab.gnome.org/GNOME/libxml2/-/issues/604" - ], - "extended_information": { - "short_description": "A use-after-free in libxml2 may lead to denial of service when parsing a crafted XML document with specific parser arguments.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "Exploiting this issue using static XML requires that the `XML_PARSE_XINCLUDE` (--xinclude) and the `XML_PARSE_VALIDATE` (--valid) flags are used.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Exploiting the vulnerability may lead to denial of service." - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS score does not take into account the contextual prerequisites required to exploit the vulnerability.", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "A PoC that triggers the use-after-free is available in the Git issue." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker must be able to control an XML file that is getting parsed by `xmlTextReaderRead()` with the xinclude and DTD validation options enabled. This can be achieved by passing both the `XML_PARSE_XINCLUDE` (--xinclude) and `XML_PARSE_VALIDATE` (--valid) flags when parsing the document.", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-45322", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-416" - ], - "cwe_details": { - "CWE-416": { - "name": "Use After Free", - "description": "Referencing memory after it has been freed can cause a program to crash, use unexpected values, or execute code.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "4" - } - ] - } - } - } - ], - "summary": "libxml2 through 2.11.5 has a use-after-free that can only occur after a certain memory allocation fails. This occurs in xmlUnlinkNode in tree.c. NOTE: the vendor's position is \"I don't think these issues are critical enough to warrant a CVE ID ... because an attacker typically can't control when memory allocations fail.\"", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1": { - "fixed_versions": [ - "[2.12.7+dfsg-1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1", - "full_path": "libxml2:2.9.14+dfsg-1.3~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-533060", - "references": [ - "https://gitlab.gnome.org/GNOME/libxml2/-/issues/583", - "http://www.openwall.com/lists/oss-security/2023/10/06/5", - "https://security-tracker.debian.org/tracker/CVE-2023-45322", - "https://gitlab.gnome.org/GNOME/libxml2/-/issues/344" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-34459" - } - ], - "summary": "An issue was discovered in xmllint (from libxml2) before 2.11.8 and 2.12.x before 2.12.7. Formatting error messages with xmllint --htmlout can result in a buffer over-read in xmlHTMLPrintFileContext in xmllint.c.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1": { - "fixed_versions": [ - "[2.12.7+dfsg-1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1", - "full_path": "libxml2:2.9.14+dfsg-1.3~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-601044", - "references": [ - "https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.12.7", - "https://security-tracker.debian.org/tracker/CVE-2024-34459", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/INKSSLW5VMZIXHRPZBAW4TJUX5SQKARG/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/VRDJCNQP32LV56KESUQ5SNZKAJWSZZRI/", - "https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.11.8", - "https://gitlab.gnome.org/GNOME/libxml2/-/issues/720", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/5HVUXKYTBWT3G5DEEQX62STJQBY367NL/" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-39615", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-119" - ], - "cwe_details": { - "CWE-119": { - "name": "Improper Restriction of Operations within the Bounds of a Memory Buffer", - "description": "The product performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "17" - } - ] - } - } - } - ], - "summary": "Xmlsoft Libxml2 v2.11.0 was discovered to contain an out-of-bounds read via the xmlSAX2StartElement() function at /libxml2/SAX2.c. This vulnerability allows attackers to cause a Denial of Service (DoS) via supplying a crafted XML file. NOTE: the vendor's position is that the product does not support the legacy SAX1 interface with custom callbacks; there is a crash even without crafted input.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1": { - "fixed_versions": [ - "[2.12.7+dfsg-1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libxml2:2.9.14+dfsg-1.3~deb12u1", - "full_path": "libxml2:2.9.14+dfsg-1.3~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-529332", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-39615", - "https://gitlab.gnome.org/GNOME/libxml2/-/issues/535" - ] - }, - { - "cves": [ - { - "cve": "CVE-2019-19882", - "cvss_v2_score": "6.9", - "cvss_v2_vector": "CVSS:2.0/AV:L/AC:M/Au:N/C:C/I:C/A:C", - "cvss_v3_score": "7.8", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-732" - ], - "cwe_details": { - "CWE-732": { - "name": "Incorrect Permission Assignment for Critical Resource", - "description": "The product specifies permissions for a security-critical resource in a way that allows that resource to be read or modified by unintended actors." - } - } - } - ], - "summary": "shadow 4.8, in certain circumstances affecting at least Gentoo, Arch Linux, and Void Linux, allows local users to obtain root access because setuid programs are misconfigured. Specifically, this affects shadow 4.8 when compiled using --with-libpam but without explicitly passing --disable-account-tools-setuid, and without a PAM configuration suitable for use with setuid account management tools. This combination leads to account management tools (groupadd, groupdel, groupmod, useradd, userdel, usermod) that can easily be used by unprivileged local users to escalate privileges to root in multiple ways. This issue became much more relevant in approximately December 2019 when an unrelated bug was fixed (i.e., the chmod calls to suidusbins were fixed in the upstream Makefile which is now included in the release version 4.8).", - "severity": "Low", - "components": { - "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1", - "full_path": "login:1:4.13+dfsg1-1+b1" - } - ] - ] - }, - "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1", - "full_path": "passwd:1:4.13+dfsg1-1+b1" - } - ] - ] - } - }, - "issue_id": "XRAY-93202", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2019-19882", - "https://github.com/shadow-maint/shadow/commit/edf7547ad5aa650be868cf2dac58944773c12d75", - "https://bugs.gentoo.org/702252", - "https://security.gentoo.org/glsa/202008-09", - "https://github.com/shadow-maint/shadow/pull/199", - "https://bugs.archlinux.org/task/64836", - "https://github.com/void-linux/void-packages/pull/17580" - ] - }, - { - "cves": [ - { - "cve": "CVE-2007-5686", - "cvss_v2_score": "4.9", - "cvss_v2_vector": "CVSS:2.0/AV:L/AC:L/Au:N/C:C/I:N/A:N", - "cwe": [ - "CWE-264" - ] - } - ], - "summary": "initscripts in rPath Linux 1 sets insecure permissions for the /var/log/btmp file, which allows local users to obtain sensitive information regarding authentication attempts. NOTE: because sshd detects the insecure permissions and does not log certain events, this also prevents sshd from logging failed authentication attempts by remote attackers.", - "severity": "Low", - "components": { - "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1", - "full_path": "login:1:4.13+dfsg1-1+b1" - } - ] - ] - }, - "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1", - "full_path": "passwd:1:4.13+dfsg1-1+b1" - } - ] - ] - } - }, - "issue_id": "XRAY-37289", - "references": [ - "http://www.securityfocus.com/archive/1/482857/100/0/threaded", - "http://www.securityfocus.com/archive/1/482129/100/100/threaded", - "http://www.securityfocus.com/bid/26048", - "http://www.vupen.com/english/advisories/2007/3474", - "https://security-tracker.debian.org/tracker/CVE-2007-5686", - "https://issues.rpath.com/browse/RPL-1825", - "http://secunia.com/advisories/27215" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-4641", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", - "cwe": [ - "CWE-287" - ], - "cwe_details": { - "CWE-287": { - "name": "Improper Authentication", - "description": "When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "13" - } - ] - } - } - } - ], - "summary": "A flaw was found in shadow-utils. When asking for a new password, shadow-utils asks the password twice. If the password fails on the second attempt, shadow-utils fails in cleaning the buffer used to store the first entry. This may allow an attacker with enough access to retrieve the password from the memory.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1", - "full_path": "login:1:4.13+dfsg1-1+b1" - } - ] - ] - }, - "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1", - "full_path": "passwd:1:4.13+dfsg1-1+b1" - } - ] - ] - } - }, - "issue_id": "XRAY-529509", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-4641", - "https://access.redhat.com/errata/RHSA-2024:2577", - "https://access.redhat.com/security/cve/CVE-2023-4641", - "https://access.redhat.com/errata/RHSA-2023:6632", - "https://bugzilla.redhat.com/show_bug.cgi?id=2215945", - "https://access.redhat.com/errata/RHSA-2024:0417", - "https://access.redhat.com/errata/RHSA-2023:7112" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-29383", - "cvss_v3_score": "3.3", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N", - "cwe": [ - "CWE-74" - ], - "cwe_details": { - "CWE-74": { - "name": "Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')", - "description": "The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component." - } - } - } - ], - "summary": "In Shadow 4.13, it is possible to inject control characters into fields provided to the SUID program chfn (change finger). Although it is not possible to exploit this directly (e.g., adding a new user fails because \\n is in the block list), it is possible to misrepresent the /etc/passwd file when viewed. Use of \\r manipulations and Unicode characters to work around blocking of the : character make it possible to give the impression that a new user has been added. In other words, an adversary may be able to convince a system administrator to take the system offline (an indirect, social-engineered denial of service) by demonstrating that \"cat /etc/passwd\" shows a rogue user account.", - "severity": "Low", - "components": { - "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:login:1:4.13+dfsg1-1+b1", - "full_path": "login:1:4.13+dfsg1-1+b1" - } - ] - ] - }, - "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:passwd:1:4.13+dfsg1-1+b1", - "full_path": "passwd:1:4.13+dfsg1-1+b1" - } - ] - ] - } - }, - "issue_id": "XRAY-513968", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-29383", - "https://github.com/shadow-maint/shadow/pull/687", - "https://github.com/shadow-maint/shadow/commit/e5905c4b84d4fb90aefcd96ee618411ebfac663d", - "https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/cve-2023-29383-abusing-linux-chfn-to-misrepresent-etc-passwd/", - "https://www.trustwave.com/en-us/resources/security-resources/security-advisories/?fid=31797" - ] - }, - { - "cves": [ - { - "cve": "CVE-2017-9937", - "cvss_v2_score": "4.3", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:N/A:P", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-119" - ], - "cwe_details": { - "CWE-119": { - "name": "Improper Restriction of Operations within the Bounds of a Memory Buffer", - "description": "The product performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "17" - } - ] - } - } - } - ], - "summary": "In LibTIFF 4.0.8, there is a memory malloc failure in tif_jbig.c. A crafted TIFF document can lead to an abort resulting in a remote denial of service attack.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libjbig0:2.1-6.1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libjbig0:2.1-6.1", - "full_path": "libjbig0:2.1-6.1" - } - ] - ] - } - }, - "issue_id": "XRAY-56874", - "references": [ - "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772%40%3Cdev.mina.apache.org%3E", - "http://bugzilla.maptools.org/show_bug.cgi?id=2707", - "https://security-tracker.debian.org/tracker/CVE-2017-9937", - "http://www.securityfocus.com/bid/99304" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-2511" - } - ], - "summary": "Issue summary: Some non-default TLS server configurations can cause unbounded\nmemory growth when processing TLSv1.3 sessions\n\nImpact summary: An attacker may exploit certain server configurations to trigger\nunbounded memory growth that would lead to a Denial of Service\n\nThis problem can occur in TLSv1.3 if the non-default SSL_OP_NO_TICKET option is\nbeing used (but not if early_data support is also configured and the default\nanti-replay protection is in use). In this case, under certain conditions, the\nsession cache can get into an incorrect state and it will fail to flush properly\nas it fills. The session cache will continue to grow in an unbounded manner. A\nmalicious client could deliberately create the scenario for this failure to\nforce a Denial of Service. It may also happen by accident in normal operation.\n\nThis issue only affects TLS servers supporting TLSv1.3. It does not affect TLS\nclients.\n\nThe FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue. OpenSSL\n1.0.2 is also not affected by this issue.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "fixed_versions": [ - "[3.0.14-1~deb12u1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-597548", - "references": [ - "https://github.com/openssl/openssl/commit/e9d7083e241670332e0443da0f0d4ffb52829f08", - "https://github.com/openssl/openssl/commit/7e4d731b1c07201ad9374c1cd9ac5263bdf35bce", - "https://github.openssl.org/openssl/extended-releases/commit/5f8d25770ae6437db119dfc951e207271a326640", - "https://github.com/openssl/openssl/commit/b52867a9f618bb955bed2a3ce3db4d4f97ed8e5d", - "https://security-tracker.debian.org/tracker/CVE-2024-2511", - "https://www.openssl.org/news/secadv/20240408.txt", - "http://www.openwall.com/lists/oss-security/2024/04/08/5", - "https://security.netapp.com/advisory/ntap-20240503-0013/" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-6129", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "Issue summary: The POLY1305 MAC (message authentication code) implementation\ncontains a bug that might corrupt the internal state of applications running\non PowerPC CPU based platforms if the CPU provides vector instructions.\n\nImpact summary: If an attacker can influence whether the POLY1305 MAC\nalgorithm is used, the application state might be corrupted with various\napplication dependent consequences.\n\nThe POLY1305 MAC (message authentication code) implementation in OpenSSL for\nPowerPC CPUs restores the contents of vector registers in a different order\nthan they are saved. Thus the contents of some of these vector registers\nare corrupted when returning to the caller. The vulnerable code is used only\non newer PowerPC processors supporting the PowerISA 2.07 instructions.\n\nThe consequences of this kind of internal application state corruption can\nbe various - from no consequences, if the calling application does not\ndepend on the contents of non-volatile XMM registers at all, to the worst\nconsequences, where the attacker could get complete control of the application\nprocess. However unless the compiler uses the vector registers for storing\npointers, the most likely consequence, if any, would be an incorrect result\nof some application dependent calculations or a crash leading to a denial of\nservice.\n\nThe POLY1305 MAC algorithm is most frequently used as part of the\nCHACHA20-POLY1305 AEAD (authenticated encryption with associated data)\nalgorithm. The most common usage of this AEAD cipher is with TLS protocol\nversions 1.2 and 1.3. If this cipher is enabled on the server a malicious\nclient can influence whether this AEAD cipher is used. This implies that\nTLS server applications using OpenSSL can be potentially impacted. However\nwe are currently not aware of any concrete application that would be affected\nby this issue therefore we consider this a Low severity security issue.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "fixed_versions": [ - "[3.0.13-1~deb12u1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-588102", - "references": [ - "https://security.netapp.com/advisory/ntap-20240426-0008/", - "https://security.netapp.com/advisory/ntap-20240426-0013/", - "http://www.openwall.com/lists/oss-security/2024/03/11/1", - "https://github.com/openssl/openssl/commit/f3fc5808fe9ff74042d639839610d03b8fdcc015", - "https://github.com/openssl/openssl/commit/050d26383d4e264966fb83428e72d5d48f402d35", - "https://security.netapp.com/advisory/ntap-20240216-0009/", - "https://www.openssl.org/news/secadv/20240109.txt", - "https://security-tracker.debian.org/tracker/CVE-2023-6129", - "https://github.com/openssl/openssl/commit/5b139f95c9a47a55a0c54100f3837b1eee942b04", - "https://security.netapp.com/advisory/ntap-20240503-0011/" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-6119" - } - ], - "summary": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "fixed_versions": [ - "[3.0.14-1~deb12u2]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-632747", - "references": [ - "https://openssl-library.org/news/secadv/20240903.txt", - "https://github.com/openssl/openssl/commit/621f3729831b05ee828a3203eddb621d014ff2b2", - "https://github.com/openssl/openssl/commit/05f360d9e849a1b277db628f1f13083a7f8dd04f", - "https://security-tracker.debian.org/tracker/CVE-2024-6119", - "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6", - "https://github.com/openssl/openssl/commit/7dfcee2cd2a63b2c64b9b4b0850be64cb695b0a0" - ], - "extended_information": { - "short_description": "Out of bounds read in OpenSSL clients can lead to denial of service when using non-default TLS verification options and connecting to malicious TLS servers", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "The fix commit contains PoC certificates that trigger the denial of service issue" - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "The attacker must make the victim client connect to their malicious TLS server, in order to serve the malformed TLS certificate. The victim client must use OpenSSL and must enable non-default certificate verification options, either -\n\n* DNS verification - by using `X509_VERIFY_PARAM_set1_host` or `X509_check_host`\n* Email verification - by using ` X509_VERIFY_PARAM_set1_email` or `X509_check_email`", - "is_positive": true - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "Denial of service of a TLS clients only. This out of bounds read cannot lead to data disclosure.", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-5363", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", - "cwe": [ - "NVD-CWE-noinfo" - ] - } - ], - "summary": "Issue summary: A bug has been identified in the processing of key and\ninitialisation vector (IV) lengths. This can lead to potential truncation\nor overruns during the initialisation of some symmetric ciphers.\n\nImpact summary: A truncation in the IV can result in non-uniqueness,\nwhich could result in loss of confidentiality for some cipher modes.\n\nWhen calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or\nEVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after\nthe key and IV have been established. Any alterations to the key length,\nvia the \"keylen\" parameter or the IV length, via the \"ivlen\" parameter,\nwithin the OSSL_PARAM array will not take effect as intended, potentially\ncausing truncation or overreading of these values. The following ciphers\nand cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.\n\nFor the CCM, GCM and OCB cipher modes, truncation of the IV can result in\nloss of confidentiality. For example, when following NIST's SP 800-38D\nsection 8.2.1 guidance for constructing a deterministic IV for AES in\nGCM mode, truncation of the counter portion could lead to IV reuse.\n\nBoth truncations and overruns of the key and overruns of the IV will\nproduce incorrect results and could, in some cases, trigger a memory\nexception. However, these issues are not currently assessed as security\ncritical.\n\nChanging the key and/or IV lengths is not considered to be a common operation\nand the vulnerable API was recently introduced. Furthermore it is likely that\napplication developers will have spotted this problem during testing since\ndecryption would fail unless both peers in the communication were similarly\nvulnerable. For these reasons we expect the probability of an application being\nvulnerable to this to be quite low. However if an application is vulnerable then\nthis issue is considered very serious. For these reasons we have assessed this\nissue as Moderate severity overall.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\n\nThe OpenSSL 3.0 and 3.1 FIPS providers are...", - "severity": "High", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "fixed_versions": [ - "[3.0.11-1~deb12u2]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-534361", - "references": [ - "https://security.netapp.com/advisory/ntap-20231027-0010/", - "https://www.openssl.org/news/secadv/20231024.txt", - "https://security-tracker.debian.org/tracker/CVE-2023-5363", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=5f69f5c65e483928c4b28ed16af6e5742929f1ee", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=0df40630850fb2740e6be6890bb905d3fc623b2d", - "https://www.debian.org/security/2023/dsa-5532", - "https://security.netapp.com/advisory/ntap-20240201-0004/", - "http://www.openwall.com/lists/oss-security/2023/10/24/1", - "https://security.netapp.com/advisory/ntap-20240201-0003/" - ], - "extended_information": { - "short_description": "A design problem in OpenSSL 3.x may lead to data leakage when processing cipher parameters.", - "full_description": "OpenSSL is an open-source cryptographic library and toolset that provides a wide range of protocol supported and functions for secure communication, data encryption, digital certificates, and other cryptographic operations, widely used in various software applications and systems.\nIn cryptography, a block cipher is a symmetric key algorithm that encrypts fixed-size blocks of data, typically 64 or 128 bits, transforming each block into a corresponding ciphertext block using a key-specific permutation.\n\nA major problem with block ciphers, is that equal plaintext blocks get transformed to equal ciphertexts. This can be used for a known-plaintext attack, where an adversary possesses both the plaintext and its corresponding encrypted form, aiming to deduce the encryption key or gain insights into the encryption algorithm.\n\nTo counter this, we use an Initialization vector (IV), which is a random or unique input to a cryptographic algorithm used to alter the first block of the cipher, ensuring equal plaintext blocks won’t be transformed to equal ciphertexts.\n\nA vulnerability was found in OpenSSL 3.x, in certain situations, parameters such as key length or IV length, will be processed after the key and IV have been established, hence they will not take effect as intended, potentially causing truncation or overreading of these values, impacting the confidentiality of the encryption.\n\nWhen calling the functions `EVP_CipherInit_ex2`, `EVP_EncryptInit_ex2, or `EVP_DecryptInit_ex2` with an `OSSL_PARAM` array, changes to the `keylen` or `ivlen` parameters will only be processed after the IV and the key have been established.\n\nNote this impacts the following ciphers: RC2, RC4, RC5, and the following cipher modes: CCM, GCM, OCB.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The vulnerability is only applicable if the vulnerable functions `EVP_CipherInit_ex2`, `EVP_EncryptInit_ex2, or `EVP_DecryptInit_ex2` is called directly or indirectly with an `OSSL_PARAM` array that alters the `ivlen` and `keylen` parameters. Moreover, it only impacts the following ciphers: RC2, RC4, RC5, and the following cipher modes: CCM, GCM, OCB.", - "is_positive": true - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "Changing the key or IV lengths is not considered a popular operation. Furthermore, the API only affects OpenSSL 3.x and it is likely the app developers have discovered the problem during testing, as it would have caused the decryption to fail.", - "is_positive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The given CVSS score does not take into account the unlikely prerequisites and the context required to exploit this CVE.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "In the case that this vulnerability is exploited successfully, an attacker can read sensitive data as plaintext, breaking the encryption." - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2024-4603" - } - ], - "summary": "Issue summary: Checking excessively long DSA keys or parameters may be very\nslow.\n\nImpact summary: Applications that use the functions EVP_PKEY_param_check()\nor EVP_PKEY_public_check() to check a DSA public key or DSA parameters may\nexperience long delays. Where the key or parameters that are being checked\nhave been obtained from an untrusted source this may lead to a Denial of\nService.\n\nThe functions EVP_PKEY_param_check() or EVP_PKEY_public_check() perform\nvarious checks on DSA parameters. Some of those computations take a long time\nif the modulus (`p` parameter) is too large.\n\nTrying to use a very large modulus is slow and OpenSSL will not allow using\npublic keys with a modulus which is over 10,000 bits in length for signature\nverification. However the key and parameter check functions do not limit\nthe modulus size when performing the checks.\n\nAn application that calls EVP_PKEY_param_check() or EVP_PKEY_public_check()\nand supplies a key or parameters obtained from an untrusted source could be\nvulnerable to a Denial of Service attack.\n\nThese functions are not called by OpenSSL itself on untrusted DSA keys so\nonly applications that directly call these functions may be vulnerable.\n\nAlso vulnerable are the OpenSSL pkey and pkeyparam command line applications\nwhen using the `-check` option.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\n\nThe OpenSSL 3.0 and 3.1 FIPS providers are affected by this issue.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "fixed_versions": [ - "[3.0.14-1~deb12u1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-601418", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-4603", - "https://security.netapp.com/advisory/ntap-20240621-0001/", - "https://github.com/openssl/openssl/commit/53ea06486d296b890d565fb971b2764fcd826e7e", - "http://www.openwall.com/lists/oss-security/2024/05/16/2", - "https://github.com/openssl/openssl/commit/3559e868e58005d15c6013a0c1fd832e51c73397", - "https://www.openssl.org/news/secadv/20240516.txt", - "https://github.com/openssl/openssl/commit/da343d0605c826ef197aceedc67e8e04f065f740", - "https://github.com/openssl/openssl/commit/9c39b3858091c152f52513c066ff2c5a47969f0d" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-0727", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "NVD-CWE-noinfo" - ] - } - ], - "summary": "Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL\nto crash leading to a potential Denial of Service attack\n\nImpact summary: Applications loading files in the PKCS12 format from untrusted\nsources might terminate abruptly.\n\nA file in PKCS12 format can contain certificates and keys and may come from an\nuntrusted source. The PKCS12 specification allows certain fields to be NULL, but\nOpenSSL does not correctly check for this case. This can lead to a NULL pointer\ndereference that results in OpenSSL crashing. If an application processes PKCS12\nfiles from an untrusted source using the OpenSSL APIs then that application will\nbe vulnerable to this issue.\n\nOpenSSL APIs that are vulnerable to this are: PKCS12_parse(),\nPKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes()\nand PKCS12_newpass().\n\nWe have also fixed a similar issue in SMIME_write_PKCS7(). However since this\nfunction is related to writing data we do not consider it security significant.\n\nThe FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "fixed_versions": [ - "[3.0.13-1~deb12u1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-589396", - "references": [ - "https://github.com/openssl/openssl/commit/d135eeab8a5dbf72b3da5240bab9ddb7678dbd2c", - "https://github.openssl.org/openssl/extended-releases/commit/03b3941d60c4bce58fab69a0c22377ab439bc0e8", - "https://security-tracker.debian.org/tracker/CVE-2024-0727", - "https://github.openssl.org/openssl/extended-releases/commit/aebaa5883e31122b404e450732dc833dc9dee539", - "https://www.openssl.org/news/secadv/20240125.txt", - "https://security.netapp.com/advisory/ntap-20240208-0006/", - "https://github.com/openssl/openssl/commit/775acfdbd0c6af9ac855f34969cdab0c0c90844a", - "https://github.com/openssl/openssl/commit/09df4395b5071217b76dc7d3d2e630eb8c5a79c2", - "http://www.openwall.com/lists/oss-security/2024/03/11/1" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-6237" - } - ], - "summary": "Issue summary: Checking excessively long invalid RSA public keys may take\na long time.\n\nImpact summary: Applications that use the function EVP_PKEY_public_check()\nto check RSA public keys may experience long delays. Where the key that\nis being checked has been obtained from an untrusted source this may lead\nto a Denial of Service.\n\nWhen function EVP_PKEY_public_check() is called on RSA public keys,\na computation is done to confirm that the RSA modulus, n, is composite.\nFor valid RSA keys, n is a product of two or more large primes and this\ncomputation completes quickly. However, if n is an overly large prime,\nthen this computation would take a long time.\n\nAn application that calls EVP_PKEY_public_check() and supplies an RSA key\nobtained from an untrusted source could be vulnerable to a Denial of Service\nattack.\n\nThe function EVP_PKEY_public_check() is not called from other OpenSSL\nfunctions however it is called from the OpenSSL pkey command line\napplication. For that reason that application is also vulnerable if used\nwith the '-pubin' and '-check' options on untrusted data.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\n\nThe OpenSSL 3.0 and 3.1 FIPS providers are affected by this issue.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "fixed_versions": [ - "[3.0.13-1~deb12u1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-588469", - "references": [ - "https://github.com/openssl/openssl/commit/a830f551557d3d66a84bbb18a5b889c640c36294", - "https://github.com/openssl/openssl/commit/18c02492138d1eb8b6548cb26e7b625fb2414a2a", - "https://github.com/openssl/openssl/commit/0b0f7abfb37350794a4b8960fafc292cd5d1b84d", - "https://security.netapp.com/advisory/ntap-20240531-0007/", - "https://www.openssl.org/news/secadv/20240115.txt", - "https://security-tracker.debian.org/tracker/CVE-2023-6237", - "http://www.openwall.com/lists/oss-security/2024/03/11/1" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-4741" - } - ], - "summary": "CVE-2024-4741", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "fixed_versions": [ - "[3.0.14-1~deb12u1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-603657", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-4741" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-5678", - "cvss_v3_score": "5.3", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", - "cwe": [ - "CWE-754" - ], - "cwe_details": { - "CWE-754": { - "name": "Improper Check for Unusual or Exceptional Conditions", - "description": "The product does not check or incorrectly checks for unusual or exceptional conditions that are not expected to occur frequently during day to day operation of the product." - } - } - } - ], - "summary": "Issue summary: Generating excessively long X9.42 DH keys or checking\nexcessively long X9.42 DH keys or parameters may be very slow.\n\nImpact summary: Applications that use the functions DH_generate_key() to\ngenerate an X9.42 DH key may experience long delays. Likewise, applications\nthat use DH_check_pub_key(), DH_check_pub_key_ex() or EVP_PKEY_public_check()\nto check an X9.42 DH key or X9.42 DH parameters may experience long delays.\nWhere the key or parameters that are being checked have been obtained from\nan untrusted source this may lead to a Denial of Service.\n\nWhile DH_check() performs all the necessary checks (as of CVE-2023-3817),\nDH_check_pub_key() doesn't make any of these checks, and is therefore\nvulnerable for excessively large P and Q parameters.\n\nLikewise, while DH_generate_key() performs a check for an excessively large\nP, it doesn't check for an excessively large Q.\n\nAn application that calls DH_generate_key() or DH_check_pub_key() and\nsupplies a key or parameters obtained from an untrusted source could be\nvulnerable to a Denial of Service attack.\n\nDH_generate_key() and DH_check_pub_key() are also called by a number of\nother OpenSSL functions. An application calling any of those other\nfunctions may similarly be affected. The other functions affected by this\nare DH_check_pub_key_ex(), EVP_PKEY_public_check(), and EVP_PKEY_generate().\n\nAlso vulnerable are the OpenSSL pkey command line application when using the\n\"-pubcheck\" option, as well as the OpenSSL genpkey command line application.\n\nThe OpenSSL SSL/TLS implementation is not affected by this issue.\n\nThe OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "fixed_versions": [ - "[3.0.13-1~deb12u1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-535129", - "references": [ - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=34efaef6c103d636ab507a0cc34dca4d3aecc055", - "https://security.netapp.com/advisory/ntap-20231130-0010/", - "http://www.openwall.com/lists/oss-security/2024/03/11/1", - "https://security-tracker.debian.org/tracker/CVE-2023-5678", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=710fee740904b6290fef0dd5536fbcedbc38ff0c", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=db925ae2e65d0d925adef429afc37f75bd1c2017", - "https://www.openssl.org/news/secadv/20231106.txt", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=ddeb4b6c6d527e54ce9a99cba785c0f7776e54b6" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-5535" - } - ], - "summary": "Issue summary: Calling the OpenSSL API function SSL_select_next_proto with an\nempty supported client protocols buffer may cause a crash or memory contents to\nbe sent to the peer.\n\nImpact summary: A buffer overread can have a range of potential consequences\nsuch as unexpected application beahviour or a crash. In particular this issue\ncould result in up to 255 bytes of arbitrary private data from memory being sent\nto the peer leading to a loss of confidentiality. However, only applications\nthat directly call the SSL_select_next_proto function with a 0 length list of\nsupported client protocols are affected by this issue. This would normally never\nbe a valid scenario and is typically not under attacker control but may occur by\naccident in the case of a configuration or programming error in the calling\napplication.\n\nThe OpenSSL API function SSL_select_next_proto is typically used by TLS\napplications that support ALPN (Application Layer Protocol Negotiation) or NPN\n(Next Protocol Negotiation). NPN is older, was never standardised and\nis deprecated in favour of ALPN. We believe that ALPN is significantly more\nwidely deployed than NPN. The SSL_select_next_proto function accepts a list of\nprotocols from the server and a list of protocols from the client and returns\nthe first protocol that appears in the server list that also appears in the\nclient list. In the case of no overlap between the two lists it returns the\nfirst item in the client list. In either case it will signal whether an overlap\nbetween the two lists was found. In the case where SSL_select_next_proto is\ncalled with a zero length client list it fails to notice this condition and\nreturns the memory immediately following the client list pointer (and reports\nthat there was no overlap in the lists).\n\nThis function is typically called from a server side application callback for\nALPN or a client side application callback for NPN. In the case of ALPN the list\nof protocols supplied by the client is guaranteed by libssl to never be zero in\nlength. The list of ...", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "fixed_versions": [ - "[3.3.2-1]" - ], - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-607811", - "references": [ - "https://security.netapp.com/advisory/ntap-20240712-0005/", - "https://www.openssl.org/news/secadv/20240627.txt", - "https://github.com/openssl/openssl/commit/cf6f91f6121f4db167405db2f0de410a456f260c", - "https://security-tracker.debian.org/tracker/CVE-2024-5535", - "http://www.openwall.com/lists/oss-security/2024/06/28/4", - "https://github.com/openssl/openssl/commit/99fb785a5f85315b95288921a321a935ea29a51e", - "http://www.openwall.com/lists/oss-security/2024/06/27/1", - "https://github.openssl.org/openssl/extended-releases/commit/b78ec0824da857223486660177d3b1f255c65d87", - "https://github.com/openssl/openssl/commit/e86ac436f0bd54d4517745483e2315650fae7b2c", - "https://github.com/openssl/openssl/commit/4ada436a1946cbb24db5ab4ca082b69c1bc10f37", - "https://github.openssl.org/openssl/extended-releases/commit/9947251413065a05189a63c9b7a6c1d4e224c21c" - ] - }, - { - "cves": [ - { - "cve": "CVE-2012-2131", - "cvss_v2_score": "7.5", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P", - "cwe": [ - "CWE-189" - ] - } - ], - "summary": "Multiple integer signedness errors in crypto/buffer/buffer.c in OpenSSL 0.9.8v allow remote attackers to conduct buffer overflow attacks, and cause a denial of service (memory corruption) or possibly have unspecified other impact, via crafted DER data, as demonstrated by an X.509 certificate or an RSA public key. NOTE: this vulnerability exists because of an incomplete fix for CVE-2012-2110.", - "severity": "High", - "components": { - "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libssl3:3.0.11-1~deb12u1", - "full_path": "libssl3:3.0.11-1~deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:openssl:3.0.11-1~deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:openssl:3.0.11-1~deb12u1", - "full_path": "openssl:3.0.11-1~deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-192416", - "references": [ - "http://www.openwall.com/lists/oss-security/2012/04/24/1", - "http://secunia.com/advisories/48956", - "http://lists.apple.com/archives/security-announce/2013/Jun/msg00000.html", - "http://www.ubuntu.com/usn/USN-1428-1", - "http://secunia.com/advisories/48895", - "http://www-01.ibm.com/support/docview.wss?uid=ssg1S1004564", - "http://www.mandriva.com/security/advisories?name=MDVSA-2012:064", - "http://www.debian.org/security/2012/dsa-2454", - "http://www.openssl.org/news/secadv_20120424.txt", - "http://lists.opensuse.org/opensuse-security-announce/2012-05/msg00014.html", - "http://lists.opensuse.org/opensuse-security-announce/2012-09/msg00007.html", - "http://www.securitytracker.com/id?1026957", - "http://secunia.com/advisories/57353", - "http://marc.info/?l=bugtraq\u0026m=134039053214295\u0026w=2", - "https://security-tracker.debian.org/tracker/CVE-2012-2131", - "http://cvs.openssl.org/chngview?cn=22479", - "http://marc.info/?l=bugtraq\u0026m=133728068926468\u0026w=2", - "http://kb.juniper.net/InfoCenter/index?page=content\u0026id=JSA10673", - "https://exchange.xforce.ibmcloud.com/vulnerabilities/75099", - "http://www.securityfocus.com/bid/53212", - "http://lists.opensuse.org/opensuse-security-announce/2012-05/msg00015.html", - "http://support.apple.com/kb/HT5784" - ] - }, - { - "cves": [ - { - "cve": "CVE-2011-3374", - "cvss_v2_score": "4.3", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:P/A:N", - "cvss_v3_score": "3.7", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N", - "cwe": [ - "CWE-347" - ], - "cwe_details": { - "CWE-347": { - "name": "Improper Verification of Cryptographic Signature", - "description": "The product does not verify, or incorrectly verifies, the cryptographic signature for data." - } - } - } - ], - "summary": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", - "severity": "Low", - "components": { - "deb://debian:bookworm:apt:2.6.1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:apt:2.6.1", - "full_path": "apt:2.6.1" - } - ] - ] - }, - "deb://debian:bookworm:libapt-pkg6.0:2.6.1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libapt-pkg6.0:2.6.1", - "full_path": "libapt-pkg6.0:2.6.1" - } - ] - ] - } - }, - "issue_id": "XRAY-34417", - "references": [ - "https://people.canonical.com/~ubuntu-security/cve/2011/CVE-2011-3374.html", - "https://seclists.org/fulldisclosure/2011/Sep/221", - "https://ubuntu.com/security/CVE-2011-3374", - "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=642480", - "https://access.redhat.com/security/cve/cve-2011-3374", - "https://snyk.io/vuln/SNYK-LINUX-APT-116518", - "https://security-tracker.debian.org/tracker/CVE-2011-3374" - ], - "extended_information": { - "short_description": "Improper signature validation in apt-key may enable Man-in-the-Middle attacks and result in code execution.", - "full_description": "`apt-key` is [`apt`](https://github.com/Debian/apt)'s key management utility, and is used to manage the keys that are used by `apt` to authenticate packages.\n\nA vulnerability in `apt-key`'s `net-update` function exists, in which [`GPG`](https://www.gnupg.org/) keys, that are used for signing packages and validating their authenticity, aren't validated correctly. The `net-update` function pulls the signing keys that should be added from an insecure location (`http://...`), exposing it to a Man-in-the-Middle attack in which malicious signing keys could be added to the system's keyring. This issue happens due to a vulnerability in the `add_keys_with_veirfy_against_master_keyring()` function, which allows adding signing keys without proper signature validation. \n\nThis vulnerability then potentially allows a malicious actor to perform a Man-in-the-Middle attack on a target, by making it validate malicious packages that were signed with the `GPG` signing key used by the attacker. Effectively, this means that `apt` can be duped to install malicious services and daemons with root privileges.\n\nThe conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man In The Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from [python-apt](https://pypi.org/project/python-apt/) Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.\n\nDo note that `apt-key` is **deprecated** and shouldn't be used, and in most Debian versions `ARCHIVE_KEYRING_URI` is not defined, making this vulnerability unexploitable in most Debian systems.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the python-apt Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", - "is_positive": true - }, - { - "name": "The issue can be exploited by attackers over the network", - "description": "This vulnerability is remotely exploitable when the applicability conditions apply." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Remote code execution is possible when the applicability conditions apply." - }, - { - "name": "The issue has an exploit published", - "description": "The reporter of this issue has provided a GPG key that can be used for an actual attack, as well as a simple PoC example." - } - ], - "remediation": "##### Deployment mitigations\n\n* Dot not execute `apt-key` command, as it is deprecated.\n* Remove the URI configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`." - } - }, - { - "cves": [ - { - "cve": "CVE-2023-4039", - "cvss_v3_score": "4.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", - "cwe": [ - "NVD-CWE-Other" - ] - } - ], - "summary": "**DISPUTED**A failure in the -fstack-protector feature in GCC-based toolchains \nthat target AArch64 allows an attacker to exploit an existing buffer \noverflow in dynamically-sized local variables in your application \nwithout this being detected. This stack-protector failure only applies \nto C99-style dynamically-sized local variables or those created using \nalloca(). The stack-protector operates as intended for statically-sized \nlocal variables.\n\nThe default behavior when the stack-protector \ndetects an overflow is to terminate your application, resulting in \ncontrolled loss of availability. An attacker who can exploit a buffer \noverflow without triggering the stack-protector might be able to change \nprogram flow control to cause an uncontrolled loss of availability or to\n go further and affect confidentiality or integrity. NOTE: The GCC project argues that this is a missed hardening bug and not a vulnerability by itself.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:gcc-12-base:12.2.0-14": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:gcc-12-base:12.2.0-14", - "full_path": "gcc-12-base:12.2.0-14" - } - ] - ] - }, - "deb://debian:bookworm:libgcc-s1:12.2.0-14": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libgcc-s1:12.2.0-14", - "full_path": "libgcc-s1:12.2.0-14" - } - ] - ] - }, - "deb://debian:bookworm:libstdc++6:12.2.0-14": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libstdc++6:12.2.0-14", - "full_path": "libstdc++6:12.2.0-14" - } - ] - ] - } - }, - "issue_id": "XRAY-531779", - "references": [ - "https://github.com/metaredteam/external-disclosures/security/advisories/GHSA-x7ch-h5rf-w2mf", - "https://developer.arm.com/Arm%20Security%20Center/GCC%20Stack%20Protector%20Vulnerability%20AArch64", - "https://security-tracker.debian.org/tracker/CVE-2023-4039" - ] - }, - { - "cves": [ - { - "cve": "CVE-2022-27943", - "cvss_v2_score": "4.3", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:N/A:P", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-674" - ], - "cwe_details": { - "CWE-674": { - "name": "Uncontrolled Recursion", - "description": "The product does not properly control the amount of recursion that takes place, consuming excessive resources, such as allocated memory or the program stack." - } - } - } - ], - "summary": "libiberty/rust-demangle.c in GNU GCC 11.2 allows stack consumption in demangle_const, as demonstrated by nm-new.", - "severity": "Low", - "components": { - "deb://debian:bookworm:gcc-12-base:12.2.0-14": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:gcc-12-base:12.2.0-14", - "full_path": "gcc-12-base:12.2.0-14" - } - ] - ] - }, - "deb://debian:bookworm:libgcc-s1:12.2.0-14": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libgcc-s1:12.2.0-14", - "full_path": "libgcc-s1:12.2.0-14" - } - ] - ] - }, - "deb://debian:bookworm:libstdc++6:12.2.0-14": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libstdc++6:12.2.0-14", - "full_path": "libstdc++6:12.2.0-14" - } - ] - ] - } - }, - "issue_id": "XRAY-203474", - "references": [ - "https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105039", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/H424YXGW7OKXS2NCAP35OP6Y4P4AW6VG/", - "https://security-tracker.debian.org/tracker/CVE-2022-27943", - "https://sourceware.org/bugzilla/show_bug.cgi?id=28995" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-28182" - } - ], - "summary": "nghttp2 is an implementation of the Hypertext Transfer Protocol version 2 in C. The nghttp2 library prior to version 1.61.0 keeps reading the unbounded number of HTTP/2 CONTINUATION frames even after a stream is reset to keep HPACK context in sync. This causes excessive CPU usage to decode HPACK stream. nghttp2 v1.61.0 mitigates this vulnerability by limiting the number of CONTINUATION frames it accepts per stream. There is no workaround for this vulnerability.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libnghttp2-14:1.52.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libnghttp2-14:1.52.0-1", - "full_path": "libnghttp2-14:1.52.0-1" - } - ] - ] - } - }, - "issue_id": "XRAY-597311", - "references": [ - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/J6ZMXUGB66VAXDW5J6QSTHM5ET25FGSA/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/PXJO2EASHM2OQQLGVDY5ZSO7UVDVHTDK/", - "https://github.com/nghttp2/nghttp2/commit/d71a4668c6bead55805d18810d633fbb98315af9", - "https://github.com/nghttp2/nghttp2/security/advisories/GHSA-x6x3-gv8h-m57q", - "https://github.com/nghttp2/nghttp2/commit/00201ecd8f982da3b67d4f6868af72a1b03b14e0", - "https://security-tracker.debian.org/tracker/CVE-2024-28182", - "https://lists.debian.org/debian-lts-announce/2024/04/msg00026.html", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/AGOME6ZXJG7664IPQNVE3DL67E3YP3HY/", - "http://www.openwall.com/lists/oss-security/2024/04/03/16" - ], - "extended_information": { - "short_description": "A design problem in the implementation of the HTTP/2 protocol in Nghttp2 may lead to denial of service by abusing frame flags.", - "full_description": "[Nghttp2](https://github.com/nghttp2/nghttp2) is an open-source implementation of HTTP/2, a significant upgrade to the HTTP protocol, offering improved efficiency and performance for web communication. It provides libraries and command-line tools for developers to integrate HTTP/2 features into their applications, including binary framing, header compression, multiplexing of requests, and server push. `Nghttp2` is widely used in various projects, such as web servers, proxies, and clients.\n\n`HTTP/2` is a binary protocol where the client and server exchange binary frames instead of text lines as in `HTTP/1.x`. `HTTP/2` resolves numerous concerns found in HTTP/1.1 by organizing each HTTP message into a series of HTTP/2 frames. These frames include frame type, length, flags, stream identifier (ID), and payload.\n\nThe `HEADERS` frame type allows sending HTTP headers of, both, request and response. The `HEADERS` frame contains many flags.\nThe `CONTINUATION` frame type is similar to the `HEADER` frame, but it has just one flag: `END_HEADERS`. When it is not set, the peer knows that more headers are coming in the following `CONTINUATION` frames.\n\nThis mechanism allows an attacker to send an `HTTP/2` stream with `CONTINUATION` frames, without setting the `END_HEADERS` flag in any of the frames. This can cause denial-of-service when sending an excessive number of these crafted frames due to caching all frames in memory.\n\nThe issue is exploitable by default due to `Nghttp2` being an `HTTP/2`-only implementation.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are either extremely common or nonexistent (always exploitable)", - "description": "Nghttp2 is vulnerable in its default configuration." - }, - { - "name": "The issue has a detailed technical explanation published, that can aid in exploit development", - "description": "A very detailed technical write-up has been published regarding the issue." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "This issue can lead to denial of service." - }, - { - "name": "The issue can be exploited by attackers over the network" - }, - { - "name": "The issue has multiple mentions in general media", - "description": "This issue is related to the well-covered attack \"HTTP/2 CONTINUATION Flood\"." - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-44487", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "NVD-CWE-noinfo" - ] - } - ], - "summary": "The HTTP/2 protocol allows a denial of service (server resource consumption) because request cancellation can reset many streams quickly, as exploited in the wild in August through October 2023.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libnghttp2-14:1.52.0-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libnghttp2-14:1.52.0-1", - "full_path": "libnghttp2-14:1.52.0-1" - } - ] - ] - } - }, - "issue_id": "XRAY-533236", - "references": [ - "https://www.debian.org/security/2023/dsa-5540", - "https://github.com/eclipse/jetty.project/issues/10679", - "https://github.com/caddyserver/caddy/releases/tag/v2.7.5", - "https://cloud.google.com/blog/products/identity-security/google-cloud-mitigated-largest-ddos-attack-peaking-above-398-million-rps/", - "https://lists.debian.org/debian-lts-announce/2023/11/msg00001.html", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/3N4NJ7FR4X4FPZUGNTQAPSTVB2HB2Y4A/", - "https://github.com/apache/tomcat/tree/main/java/org/apache/coyote/http2", - "https://news.ycombinator.com/item?id=37830998", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LNMZJCDHGLJJLXO4OXWJMTVQRNWOC7UL/", - "https://github.com/dotnet/core/blob/e4613450ea0da7fd2fc6b61dfb2c1c1dec1ce9ec/release-notes/6.0/6.0.23/6.0.23.md?plain=1#L73", - "https://lists.debian.org/debian-lts-announce/2023/10/msg00024.html", - "http://www.openwall.com/lists/oss-security/2023/10/13/4", - "https://access.redhat.com/security/cve/cve-2023-44487", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/ZLU6U2R2IC2K64NDPNMV55AUAO65MAF4/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/2MBEPPC36UBVOZZNAXFHKLFGSLCMN5LI/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/ZKQSIKIAT5TJ3WSLU3RDBQ35YX4GY4V3/", - "https://lists.apache.org/thread/5py8h42mxfsn8l1wy6o41xwhsjlsd87q", - "https://edg.io/lp/blog/resets-leaks-ddos-and-the-tale-of-a-hidden-cve", - "https://cgit.freebsd.org/ports/commit/?id=c64c329c2c1752f46b73e3e6ce9f4329be6629f9", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/KSEGD2IWKNUO3DWY4KQGUQM5BISRWHQE/", - "https://github.com/micrictor/http2-rst-stream", - "https://github.com/nghttp2/nghttp2/releases/tag/v1.57.0", - "http://www.openwall.com/lists/oss-security/2023/10/13/9", - "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-44487", - "https://bugzilla.proxmox.com/show_bug.cgi?id=4988", - "https://news.ycombinator.com/item?id=37830987", - "https://blog.vespa.ai/cve-2023-44487/", - "https://github.com/tempesta-tech/tempesta/issues/1986", - "https://groups.google.com/g/golang-announce/c/iNNxDTCjZvo", - "https://linkerd.io/2023/10/12/linkerd-cve-2023-44487/", - "https://github.com/kazu-yamamoto/http2/issues/93", - "https://github.com/Kong/kong/discussions/11741", - "https://www.cisa.gov/news-events/alerts/2023/10/10/http2-rapid-reset-vulnerability-cve-2023-44487", - "https://github.com/envoyproxy/envoy/pull/30055", - "https://lists.debian.org/debian-lts-announce/2023/10/msg00045.html", - "https://openssf.org/blog/2023/10/10/http-2-rapid-reset-vulnerability-highlights-need-for-rapid-response/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/FNA62Q767CFAFHBCDKYNPBMZWB7TWYVU/", - "https://lists.debian.org/debian-lts-announce/2023/10/msg00023.html", - "https://www.debian.org/security/2023/dsa-5558", - "https://blog.litespeedtech.com/2023/10/11/rapid-reset-http-2-vulnerablilty/", - "https://security.gentoo.org/glsa/202311-09", - "https://bugzilla.suse.com/show_bug.cgi?id=1216123", - "https://www.darkreading.com/cloud/internet-wide-zero-day-bug-fuels-largest-ever-ddos-event", - "https://github.com/projectcontour/contour/pull/5826", - "https://github.com/golang/go/issues/63417", - "https://github.com/netty/netty/commit/58f75f665aa81a8cbcf6ffa74820042a285c5e61", - "https://blog.cloudflare.com/zero-day-rapid-reset-http2-record-breaking-ddos-attack/", - "https://ubuntu.com/security/CVE-2023-44487", - "https://martinthomson.github.io/h2-stream-limits/draft-thomson-httpbis-h2-stream-limits.html", - "https://www.debian.org/security/2023/dsa-5521", - "https://www.debian.org/security/2023/dsa-5570", - "https://github.com/h2o/h2o/pull/3291", - "https://github.com/oqtane/oqtane.framework/discussions/3367", - "https://github.com/opensearch-project/data-prepper/issues/3474", - "https://github.com/advisories/GHSA-vx74-f528-fxqg", - "https://bugzilla.redhat.com/show_bug.cgi?id=2242803", - "https://github.com/etcd-io/etcd/issues/16740", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/CLB4TW7KALB3EEQWNWCN7OUIWWVWWCG2/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/BFQD3KUEMFBHPAPBGLWQC34L4OWL5HAZ/", - "https://github.com/icing/mod_h2/blob/0a864782af0a942aa2ad4ed960a6b32cd35bcf0a/mod_http2/README.md?plain=1#L239-L244", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LKYHSZQFDNR7RSA7LHVLLIAQMVYCUGBG/", - "https://github.com/apache/trafficserver/pull/10564", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/VSRDIV77HNKUSM7SJC5BKE5JSHLHU2NK/", - "https://lists.debian.org/debian-lts-announce/2023/10/msg00020.html", - "https://istio.io/latest/news/security/istio-security-2023-004/", - "https://news.ycombinator.com/item?id=37837043", - "https://security.netapp.com/advisory/ntap-20240621-0007/", - "https://discuss.hashicorp.com/t/hcsec-2023-32-vault-consul-and-boundary-affected-by-http-2-rapid-reset-denial-of-service-vulnerability-cve-2023-44487/59715", - "https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/", - "https://github.com/dotnet/announcements/issues/277", - "http://www.openwall.com/lists/oss-security/2023/10/20/8", - "https://github.com/kubernetes/kubernetes/pull/121120", - "https://security.paloaltonetworks.com/CVE-2023-44487", - "https://www.nginx.com/blog/http-2-rapid-reset-attack-impacting-f5-nginx-products/", - "https://www.theregister.com/2023/10/10/http2_rapid_reset_zeroday/", - "https://github.com/junkurihara/rust-rpxy/issues/97", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/JIZSEFC3YKCGABA2BZW6ZJRMDZJMB7PJ/", - "https://community.traefik.io/t/is-traefik-vulnerable-to-cve-2023-44487/20125", - "http://www.openwall.com/lists/oss-security/2023/10/18/4", - "https://lists.w3.org/Archives/Public/ietf-http-wg/2023OctDec/0025.html", - "https://github.com/facebook/proxygen/pull/466", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/X6QXN4ORIVF6XBW4WWFE7VNPVC74S45Y/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/VHUHTSXLXGXS7JYKBXTA3VINUPHTNGVU/", - "https://lists.debian.org/debian-lts-announce/2023/10/msg00047.html", - "https://lists.debian.org/debian-lts-announce/2023/11/msg00012.html", - "https://msrc.microsoft.com/blog/2023/10/microsoft-response-to-distributed-denial-of-service-ddos-attacks-against-http/2/", - "https://tomcat.apache.org/security-10.html#Fixed_in_Apache_Tomcat_10.1.14", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/ZB43REMKRQR62NJEI7I5NQ4FSXNLBKRT/", - "https://github.com/advisories/GHSA-qppj-fm5r-hxr3", - "https://aws.amazon.com/security/security-bulletins/AWS-2023-011/", - "https://blog.qualys.com/vulnerabilities-threat-research/2023/10/10/cve-2023-44487-http-2-rapid-reset-attack", - "https://cloud.google.com/blog/products/identity-security/how-it-works-the-novel-http2-rapid-reset-ddos-attack", - "https://news.ycombinator.com/item?id=37831062", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/E72T67UPDRXHIDLO3OROR25YAMN4GGW5/", - "https://github.com/alibaba/tengine/issues/1872", - "http://www.openwall.com/lists/oss-security/2023/10/18/8", - "https://github.com/advisories/GHSA-xpw8-rcwv-8f8p", - "https://github.com/microsoft/CBL-Mariner/pull/6381", - "https://www.debian.org/security/2023/dsa-5549", - "https://security.netapp.com/advisory/ntap-20240426-0007/", - "https://github.com/kazu-yamamoto/http2/commit/f61d41a502bd0f60eb24e1ce14edc7b6df6722a1", - "https://security.netapp.com/advisory/ntap-20240621-0006/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/HT7T2R4MQKLIF4ODV4BDLPARWFPCJ5CZ/", - "https://gist.github.com/adulau/7c2bfb8e9cdbe4b35a5e131c66a0c088", - "https://www.netlify.com/blog/netlify-successfully-mitigates-cve-2023-44487/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/XFOIBB4YFICHDM7IBOP7PWXW3FX4HLL2/", - "https://security.netapp.com/advisory/ntap-20231016-0001/", - "https://www.haproxy.com/blog/haproxy-is-not-affected-by-the-http-2-rapid-reset-attack-cve-2023-44487", - "https://github.com/nghttp2/nghttp2/pull/1961", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/JMEXY22BFG5Q64HQCM5CK2Q7KDKVV4TY/", - "https://github.com/apache/httpd-site/pull/10", - "https://my.f5.com/manage/s/article/K000137106", - "https://github.com/akka/akka-http/issues/4323", - "https://arstechnica.com/security/2023/10/how-ddosers-used-the-http-2-protocol-to-deliver-attacks-of-unprecedented-size/", - "https://github.com/arkrwn/PoC/tree/main/CVE-2023-44487", - "https://www.bleepingcomputer.com/news/security/new-http-2-rapid-reset-zero-day-attack-breaks-ddos-records/", - "https://github.com/line/armeria/pull/5232", - "https://security-tracker.debian.org/tracker/CVE-2023-44487", - "https://github.com/apache/httpd/blob/afcdbeebbff4b0c50ea26cdd16e178c0d1f24152/modules/http2/h2_mplx.c#L1101-L1113", - "https://www.openwall.com/lists/oss-security/2023/10/10/6", - "https://github.com/grpc/grpc-go/pull/6703", - "https://github.com/caddyserver/caddy/issues/5877", - "https://github.com/Azure/AKS/issues/3947", - "https://github.com/nodejs/node/pull/50121", - "https://github.com/haproxy/haproxy/issues/2312", - "https://github.com/ninenines/cowboy/issues/1615", - "http://www.openwall.com/lists/oss-security/2023/10/19/6", - "https://github.com/h2o/h2o/security/advisories/GHSA-2m7v-gc89-fjqf", - "https://mailman.nginx.org/pipermail/nginx-devel/2023-October/S36Q5HBXR7CAIMPLLPRSSSYR4PCMWILK.html", - "https://github.com/openresty/openresty/issues/930", - "https://github.com/bcdannyboy/CVE-2023-44487", - "https://forums.swift.org/t/swift-nio-http2-security-update-cve-2023-44487-http-2-dos/67764", - "https://github.com/linkerd/website/pull/1695/commits/4b9c6836471bc8270ab48aae6fd2181bc73fd632", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/WE2I52RHNNU42PX6NZ2RBUHSFFJ2LVZX/", - "https://www.debian.org/security/2023/dsa-5522", - "https://www.phoronix.com/news/HTTP2-Rapid-Reset-Attack", - "https://seanmonstar.com/post/730794151136935936/hyper-http2-rapid-reset-unaffected", - "https://netty.io/news/2023/10/10/4-1-100-Final.html", - "https://github.com/varnishcache/varnish-cache/issues/3996", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/WLPRQ5TWUQQXYWBJM7ECYDAIL2YVKIUH/", - "https://github.com/apache/apisix/issues/10320" - ], - "extended_information": { - "short_description": "A design problem in the implementation of the HTTP/2 protocol may lead to DoS and ease the possibility of DDoS in web server applications by abusing request cancellation.", - "full_description": "[The HTTP (Hypertext Transfer Protocol)](https://developer.mozilla.org/en-US/docs/Web/HTTP) is a fundamental protocol of the World Wide Web, enabling the exchange of data between a client (typically a web browser) and a server. It defines the rules for requesting and transmitting web pages and other resources over the internet. Request and response messages are exchanged as a stream of ASCII characters, sent over a reliable transport layer like TCP.\n\n[HTTP/2](https://http2.github.io/) is a modern network protocol designed to improve the performance and efficiency of web communication. It replaces the older HTTP/1.1 protocol and introduces features like header compression and enhanced request cancellation mechanisms, which collectively enhance the speed and responsiveness of websites.\n\nThis request cancellation mechanism allows clients to terminate unnecessary or redundant requests without waiting for a server's response, reducing network congestion and further improving the overall responsiveness of web applications.\n\nHTTP/2 resolves numerous concerns found in HTTP/1.1 by organizing each HTTP message into a series of HTTP/2 frames. These frames include type, length, flags, stream identifier (ID), and payload. The stream ID is essential in clearly associating specific bytes on the network with their corresponding messages, facilitating secure multiplexing and concurrent processing. These streams are bidirectional, enabling clients to transmit frames, and servers to respond with frames using the same ID.\n\nAs detailed in [this technical analysis](https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/), there's a vulnerability in the way request cancellation is implemented. The flaw lies in the process of sending an excessive number of requests (specifically, `HEADERS` frames), each immediately followed by a request cancellation frame utilizing the `RST_STREAM` frame. This sequence rapidly leads to a substantial consumption of server-side resources. Consequently, this vulnerability amplifies the risk of Distributed Denial of Service (DDoS) attacks, making it easier to overwhelm and exhaust the server's available resources.\n\nA lot of server applications are vulnerable to the Http/2 Rapid Reset attack.\nHowever, note that HTTP/2 must be enabled, which is not the default configuration on most applications (excluding nghttp2 for example).\nA non-exhaustive list of these vulnerable web applications:\n```\n- Tomcat\n- Jetty\n- NGINX on certain conditions\n- nghttp2\n- Netty\n```", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has been reported to be actively exploited in public networks", - "description": "Cloudflare identified this vulnerability being exploited in a DDoS attack of unprecedented scale on August 25, 2023, which surpassed their previous largest recorded attack by almost threefold." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker should attack a web server application with HTTP/2 protocol enabled and no (or a high) keepalive-requests options.", - "is_positive": true - }, - { - "name": "The issue can be exploited by attackers over the network" - }, - { - "name": "The issue has an exploit published", - "description": "A [PoC exists](https://github.com/imabee101/CVE-2023-44487) for this issue" - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "This issue can lead to DoS on popular server applications using HTTP/2 protocol and ease the possibility of DDoS attack." - }, - { - "name": "The issue has multiple mentions in general media", - "description": "The vulnerability received extensive media coverage from Google, Cloudflare, and more." - } - ], - "remediation": "##### Deployment mitigations\n\nA possible mitigation is to limit the maximum number of requests that can be made over a single keep-alive connection.\n\n##### Deployment mitigations\n\nFor NGINX:\n\nDisabling HTTP/2 in NGINX is not necessary. Simply ensure you have configured:\n\n- `keepalive_requests` should be kept at the default setting of 1000 requests\n- `http2_max_concurrent_streams` should be kept at the default setting of 128 streams\n- `limit_conn` and `limit_req` should be set \"with a reasonable setting balancing application performance and security\"\n\n##### Development mitigations\n\nFor Nghttp2:\nImplement `nghttp2_on_frame_recv_callback` callback function, and check and count `RST_STREAM` frames. If an excessive number of `RST_STREAM` frames are received, then take action, such as dropping the connection silently, or calling `nghttp2_submit_goaway` and gracefully terminate the connection.\n```c\n#include \u003cnghttp2/nghttp2.h\u003e\n\n// Callback function for handling frame reception\nint on_frame_recv_callback(nghttp2_session* session,\n const nghttp2_frame* frame, void* user_data) {\n // Check if the received frame is an RST_STREAM frame\n if (frame-\u003ehd.type == NGHTTP2_RST_STREAM) {\n // Increment a counter for RST_STREAM frames\n int* rst_stream_counter = (int*)user_data;\n (*rst_stream_counter)++;\n \n // Define a threshold for excessive RST_STREAM frames\n int rst_stream_threshold = 10; // Adjust this value as needed\n \n // If the threshold is exceeded, take action (e.g., close the connection)\n if (*rst_stream_counter \u003e rst_stream_threshold) {\n // Here, you can choose to close the connection gracefully or drop it\n // For demonstration purposes, we'll just print a message\n printf(\"Excessive RST_STREAM frames received. Closing the connection.\\n\");\n // You can call nghttp2_submit_goaway() to send a GOAWAY frame if needed.\n // nghttp2_submit_goaway(session, NGHTTP2_FLAG_NONE, error_code, opaque_data);\n // Then, close the connection.\n }\n }\n \n // Continue processing other frames if needed\n return 0;\n}\n\nint main() {\n // Initialize nghttp2_session and set up the on_frame_recv_callback\n nghttp2_session* session;\n int rst_stream_counter = 0;\n \n // Initialize nghttp2_session, set up callbacks, etc.\n // ...\n\n // Set the user data to be passed to the callback\n nghttp2_session_user_data(session, \u0026rst_stream_counter);\n \n // Register the on_frame_recv_callback\n nghttp2_session_callbacks* callbacks;\n nghttp2_session_callbacks_new(\u0026callbacks);\n nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks, on_frame_recv_callback);\n // Other callback registrations here...\n \n // Attach the callbacks to the session\n nghttp2_session_server_new(\u0026session, callbacks, \u0026rst_stream_counter);\n \n // Start processing HTTP/2 frames\n // ...\n\n // Cleanup and finish the program\n // ...\n\n return 0;\n}\n```\n\n##### Development mitigations\n\nFor Golang:\n\nThe default stream concurrency limit in `golang` is `250 streams (requests) per HTTP/2 connection`. This value may be adjusted in the `golang.org/x/net/http2` package using the `Server.MaxConcurrentStreams` setting and the `ConfigureServer` function which are available in `golang.org/x/net/http2`.\n\n```go\nimport (\n\t\"fmt\"\n\t\"golang.org/x/net/http2\"\n\t\"net/http\"\n)\n\nfunc main() {\n\t// Create an HTTP/2 server instance\n\thttp2Server := \u0026http2.Server{}\n\n\t// Set the desired stream concurrency limit\n\tmaxConcurrentStreams := 500 // Change this to your desired limit\n\thttp2Server.MaxConcurrentStreams = uint32(maxConcurrentStreams)\n\n\t// Configure an HTTP server to use HTTP/2 with the adjusted settings\n\tserver := \u0026http.Server{\n\t\tAddr: \":8080\",\n\t\tHandler: http.HandlerFunc(handleRequest),\n\t}\n\thttp2.ConfigureServer(server, http2Server)\n\n\t// Start the HTTP server\n\terr := server.ListenAndServeTLS(\"cert.pem\", \"key.pem\")\n\tif err != nil {\n\t\tfmt.Println(\"Error:\", err)\n\t}\n}\n```\n\n##### Development mitigations\n\nFor netty:\n```java\nimport io.netty.handler.codec.http2.Http2FrameListener;\nimport io.netty.handler.codec.http2.Http2FrameStream;\nimport io.netty.handler.codec.http2.Http2ResetFrame;\nimport io.netty.handler.codec.http2.Http2HeadersFrame;\n\npublic class CustomHttp2FrameListener implements Http2FrameListener {\n private int rstFrameCount = 0;\n private int maxRstFrameCount = 10; // Adjust this to your desired limit\n private long resetTimeMillis = System.currentTimeMillis();\n private long resetTimeIntervalMillis = 60000; // 60 seconds\n\n @Override\n public int onDataRead(Http2FrameStream stream, byte[] data, int padding, boolean endOfStream) {\n // Handle data frames if needed\n return 0;\n }\n\n @Override\n public void onHeadersRead(Http2FrameStream stream, Http2HeadersFrame headersFrame) {\n // Handle headers frames if needed\n }\n\n @Override\n public void onHeadersRead(Http2FrameStream stream, Http2HeadersFrame headersFrame, boolean endOfStream) {\n // Handle headers frames if needed\n }\n\n @Override\n public void onRstStreamRead(Http2FrameStream stream, Http2ResetFrame resetFrame) {\n long currentTimeMillis = System.currentTimeMillis();\n \n // Check if the reset time interval has passed, and reset the count if needed\n if (currentTimeMillis - resetTimeMillis \u003e= resetTimeIntervalMillis) {\n rstFrameCount = 0;\n resetTimeMillis = currentTimeMillis;\n }\n \n rstFrameCount++;\n \n // Check if the count exceeds the limit\n if (rstFrameCount \u003e maxRstFrameCount) {\n // Take action, e.g., close the connection, log, or drop frames\n // You can use stream or resetFrame to get more context if needed.\n // To close the connection, you can use stream.connection().close();\n }\n }\n}\n```" - } - }, - { - "cves": [ - { - "cve": "CVE-2023-45853", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-190" - ], - "cwe_details": { - "CWE-190": { - "name": "Integer Overflow or Wraparound", - "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "14" - } - ] - } - } - } - ], - "summary": "MiniZip in zlib through 1.3 has an integer overflow and resultant heap-based buffer overflow in zipOpenNewFileInZip4_64 via a long filename, comment, or extra field. NOTE: MiniZip is not a supported part of the zlib product. NOTE: pyminizip through 0.2.6 is also vulnerable because it bundles an affected zlib version, and exposes the applicable MiniZip code through its compress API.", - "severity": "Critical", - "components": { - "deb://debian:bookworm:zlib1g:1:1.2.13.dfsg-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:zlib1g:1:1.2.13.dfsg-1", - "full_path": "zlib1g:1:1.2.13.dfsg-1" - } - ] - ] - } - }, - "issue_id": "XRAY-533715", - "references": [ - "http://www.openwall.com/lists/oss-security/2024/01/24/10", - "http://www.openwall.com/lists/oss-security/2023/10/20/9", - "https://github.com/madler/zlib/blob/ac8f12c97d1afd9bafa9c710f827d40a407d3266/contrib/README.contrib#L1-L4", - "https://www.winimage.com/zLibDll/minizip.html", - "https://chromium.googlesource.com/chromium/src/+/de29dd6c7151d3cd37cb4cf0036800ddfb1d8b61", - "https://pypi.org/project/pyminizip/#history", - "https://lists.debian.org/debian-lts-announce/2023/11/msg00026.html", - "https://security.gentoo.org/glsa/202401-18", - "https://chromium.googlesource.com/chromium/src/+/d709fb23806858847131027da95ef4c548813356", - "https://github.com/madler/zlib/pull/843", - "https://security.netapp.com/advisory/ntap-20231130-0009/", - "https://security-tracker.debian.org/tracker/CVE-2023-45853" - ], - "extended_information": { - "short_description": "A heap buffer overflow in zlib may lead to remote code execution when parsing a malicious archive.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "PoC demonstrates a heap overflow that crashes the application. Although not demonstrated, it is likely that an RCE exploit could be developed, since zip-processing may allow many heap-shaping primitives needed for a full RCE exploit." - }, - { - "name": "The issue can be exploited by attackers over the network", - "description": "An attacker could compromise a server that is using the `zlib` library to zip or unzip any files." - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS score does not reflect the context-dependent nature of this vulnerability.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Remote code execution." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "An attacker must find a way to upload a crafted zip archive, that is subsequently processed by the vulnerable `zipOpenNewFileInZip4_64` function.", - "is_positive": true - } - ], - "remediation": "##### Development mitigations\n\nMake sure that files with names larger than 65536 characters are not parsed using `zlib`.\n\nAlso, a fix currently exists in the `develop` branch of `zlib` and can be deployed manually." - } - }, - { - "cves": [ - { - "cve": "CVE-2024-37371", - "cvss_v3_score": "9.1", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H", - "cwe": [ - "NVD-CWE-Other" - ] - } - ], - "summary": "In MIT Kerberos 5 (aka krb5) before 1.21.3, an attacker can cause invalid memory reads during GSS message token handling by sending message tokens with invalid length fields.", - "severity": "Critical", - "components": { - "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", - "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", - "full_path": "libk5crypto3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", - "full_path": "libkrb5-3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", - "full_path": "libkrb5support0:1.20.1-2+deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-607813", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-37371", - "https://web.mit.edu/kerberos/www/advisories/", - "https://github.com/krb5/krb5/commit/55fbf435edbe2e92dd8101669b1ce7144bc96fef" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-37370", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", - "cwe": [ - "NVD-CWE-noinfo" - ] - } - ], - "summary": "In MIT Kerberos 5 (aka krb5) before 1.21.3, an attacker can modify the plaintext Extra Count field of a confidential GSS krb5 wrap token, causing the unwrapped token to appear truncated to the application.", - "severity": "High", - "components": { - "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", - "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", - "full_path": "libk5crypto3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", - "full_path": "libkrb5-3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", - "full_path": "libkrb5support0:1.20.1-2+deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-607812", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-37370", - "https://web.mit.edu/kerberos/www/advisories/", - "https://github.com/krb5/krb5/commit/55fbf435edbe2e92dd8101669b1ce7144bc96fef" - ] - }, - { - "cves": [ - { - "cve": "CVE-2011-0283", - "cvss_v2_score": "5.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P", - "cwe": [ - "NVD-CWE-Other" - ] - } - ], - "summary": "The Key Distribution Center (KDC) in MIT Kerberos 5 (aka krb5) 1.9 allows remote attackers to cause a denial of service (NULL pointer dereference and daemon crash) via a malformed request packet that does not trigger a response packet.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", - "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", - "full_path": "libk5crypto3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", - "full_path": "libkrb5-3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", - "full_path": "libkrb5support0:1.20.1-2+deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-515010", - "references": [ - "http://web.mit.edu/kerberos/advisories/MITKRB5-SA-2011-002.txt", - "http://www.securityfocus.com/bid/46272", - "http://securityreason.com/securityalert/8073", - "http://www.vupen.com/english/advisories/2011/0330", - "http://secunia.com/advisories/43260", - "http://www.securitytracker.com/id?1025037", - "http://www.securityfocus.com/archive/1/516299/100/0/threaded", - "https://security-tracker.debian.org/tracker/CVE-2011-0283" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-26462" - } - ], - "summary": "Kerberos 5 (aka krb5) 1.21.2 contains a memory leak vulnerability in /krb5/src/kdc/ndr.c.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", - "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", - "full_path": "libk5crypto3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", - "full_path": "libkrb5-3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", - "full_path": "libkrb5support0:1.20.1-2+deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-592118", - "references": [ - "https://security.netapp.com/advisory/ntap-20240415-0012/", - "https://github.com/LuMingYinDetect/krb5_defects/blob/main/krb5_detect_3.md", - "https://security-tracker.debian.org/tracker/CVE-2024-26462" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-26458" - } - ], - "summary": "Kerberos 5 (aka krb5) 1.21.2 contains a memory leak in /krb5/src/lib/rpc/pmap_rmt.c.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", - "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", - "full_path": "libk5crypto3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", - "full_path": "libkrb5-3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", - "full_path": "libkrb5support0:1.20.1-2+deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-592120", - "references": [ - "https://github.com/LuMingYinDetect/krb5_defects/blob/main/krb5_detect_1.md", - "https://security-tracker.debian.org/tracker/CVE-2024-26458", - "https://security.netapp.com/advisory/ntap-20240415-0010/" - ] - }, - { - "cves": [ - { - "cve": "CVE-2018-5709", - "cvss_v2_score": "5.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:P/A:N", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", - "cwe": [ - "CWE-190" - ], - "cwe_details": { - "CWE-190": { - "name": "Integer Overflow or Wraparound", - "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "14" - } - ] - } - } - } - ], - "summary": "An issue was discovered in MIT Kerberos 5 (aka krb5) through 1.16. There is a variable \"dbentry-\u003en_key_data\" in kadmin/dbutil/dump.c that can store 16-bit data but unknowingly the developer has assigned a \"u4\" variable to it, which is for 32-bit data. An attacker can use this vulnerability to affect other artifacts of the database as we know that a Kerberos database dump file contains trusted data.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", - "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", - "full_path": "libk5crypto3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", - "full_path": "libkrb5-3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", - "full_path": "libkrb5support0:1.20.1-2+deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-60750", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2018-5709", - "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772%40%3Cdev.mina.apache.org%3E", - "https://github.com/poojamnit/Kerberos-V5-1.16-Vulnerabilities/tree/master/Integer%20Overflow" - ], - "extended_information": { - "short_description": "(Non-issue) Integer truncation in Kerberos5 leads to no impact when processing a crafted Kerberos5 beta7 format database file.", - "full_description": "[Kerberos](https://web.mit.edu/kerberos/) is a network authentication protocol. It is designed to provide strong authentication for client/server applications by using secret-key cryptography. A free implementation of this protocol is available from the Massachusetts Institute of Technology. Kerberos is available in many commercial products as well.\n\nA [Kerberos database](https://web.mit.edu/kerberos/krb5-1.12/doc/admin/database.html) contains all of a realm’s Kerberos principals, their passwords, and other administrative information about each principal. For the most part, you will use the `kdb5_util` program to manipulate the Kerberos database as a whole, and the `kadmin` program to make changes to the entries in the database. \n\nIn `kdb5_util`, there is a `process_k5beta7_princ` method responsible for adding Kerberos 5 beta 7 format data from a file to the Kerberos database. This function is vulnerable to integer overflow as a Database entry defined on 16-bits is assigned a 32-bits value from the given file. It turns out that it does not have any impact at all and it is not a security flaw.\n\nOriginally, the vulnerability was mistakenly reported as an Integer Overflow.\nThe issue should not affect any other data allocated close to the 16-bit integer in question. Furthermore, a negative value of the 16-bit integer does not impact the flow of the program in any meaningful way.\n\nTo trigger the integer truncation, an attacker has to get the user to use the `kdb5_util` utility to restore a Kerberos 5 - beta 7 format - database from a crafted malicious file. It can be done using the following command:\n```\nkdb5_util load -d DB_NAME DB_FILE \n```", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "Exploiting the issue requires the user to interact with the vulnerable software", - "description": "Requires the user to restore the Kerberos Database from a crafted malicious file, which is unlikely.", - "is_positive": true - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "The integer truncation doesn't affect data allocated near the 16-bit integer and doesn't have any meaningful impact.", - "is_positive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS does not reflect the fact that the vulnerability does not have any security impact.", - "is_positive": true - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "A Kerberos database is not restored often. The attacker must find a way to get the user to restore the database from a crafted file. If the attacker has access to the backup file, it can be modified even without exploiting this vulnerability. The vulnerability only helps by making the attacker's modifications to the backup file seem legitimate when manually inspected.", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2024-26461" - } - ], - "summary": "Kerberos 5 (aka krb5) 1.21.2 contains a memory leak vulnerability in /krb5/src/lib/gssapi/krb5/k5sealv3.c.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libgssapi-krb5-2:1.20.1-2+deb12u1", - "full_path": "libgssapi-krb5-2:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libk5crypto3:1.20.1-2+deb12u1", - "full_path": "libk5crypto3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5-3:1.20.1-2+deb12u1", - "full_path": "libkrb5-3:1.20.1-2+deb12u1" - } - ] - ] - }, - "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libkrb5support0:1.20.1-2+deb12u1", - "full_path": "libkrb5support0:1.20.1-2+deb12u1" - } - ] - ] - } - }, - "issue_id": "XRAY-592121", - "references": [ - "https://github.com/LuMingYinDetect/krb5_defects/blob/main/krb5_detect_2.md", - "https://security.netapp.com/advisory/ntap-20240415-0011/", - "https://security-tracker.debian.org/tracker/CVE-2024-26461" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-38950" - } - ], - "summary": "Heap Buffer Overflow vulnerability in Libde265 v1.0.15 allows attackers to crash the application via crafted payload to __interceptor_memcpy function.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "issue_id": "XRAY-607770", - "references": [ - "https://github.com/strukturag/libde265/issues/460", - "https://security-tracker.debian.org/tracker/CVE-2024-38950", - "https://github.com/zhangteng0526/CVE-information/blob/main/CVE-2024-38950" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-51792" - } - ], - "summary": "Buffer Overflow vulnerability in libde265 v1.0.12 allows a local attacker to cause a denial of service via the allocation size exceeding the maximum supported size of 0x10000000000.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "issue_id": "XRAY-599139", - "references": [ - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LE3ASLH6QF2E5OVJI5VA3JSEPJFFFMNY/", - "https://github.com/strukturag/libde265", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/IPETICRXUOGRIM4U3BCRTIKE3IZWCSBT/", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/6G7EYH2JAK5OJPVNC6AXYQ5K7YGYNCDN/", - "https://github.com/strukturag/libde265/issues/427", - "https://security-tracker.debian.org/tracker/CVE-2023-51792" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-49465", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "Libde265 v1.0.14 was discovered to contain a heap-buffer-overflow vulnerability in the derive_spatial_luma_vector_prediction function at motion.cc.", - "severity": "High", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "issue_id": "XRAY-540366", - "references": [ - "https://github.com/strukturag/libde265/issues/435", - "https://lists.debian.org/debian-lts-announce/2023/12/msg00022.html", - "https://security-tracker.debian.org/tracker/CVE-2023-49465" - ], - "extended_information": { - "short_description": "A non-proven heap buffer overflow in libde265 may lead to remote code execution when parsing attacker-supplied H.265 data.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "description": "The attacker must be able to provide remote input that will be parsed by H.265, for example - `./dec265 attacker_input`.\nThe exploit only works on a small percent of executions, since the impact of parsing a malicious Atari DEGAS Elite bitmap file is contingent on the current heap state.", - "is_positive": true - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Although a PoC was linked to the issue, the maintainer was not able to reproduce the corruption. In addition, the heap buffer overflow was not proven to be able to cause remote code execution.", - "is_positive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS does not take into account the non-trivial exploitation.", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-43887", - "cvss_v3_score": "8.1", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H", - "cwe": [ - "CWE-120" - ], - "cwe_details": { - "CWE-120": { - "name": "Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')", - "description": "The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow." - } - } - } - ], - "summary": "Libde265 v1.0.12 was discovered to contain multiple buffer overflows via the num_tile_columns and num_tile_row parameters in the function pic_parameter_set::dump.", - "severity": "High", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "issue_id": "XRAY-538327", - "references": [ - "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html", - "https://security-tracker.debian.org/tracker/CVE-2023-43887", - "https://github.com/strukturag/libde265/issues/418", - "https://github.com/strukturag/libde265/commit/63b596c915977f038eafd7647d1db25488a8c133" - ], - "extended_information": { - "short_description": "An out of bounds read in libde265 may lead to denial of service or data leakage when decoding attacker-supplied data in a non-default configuration.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker has to be able to decode crafted H.265 files with the non-default dump headers option enabled. For example - `./dec265 -d attacker_input`", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "The Github issue has a linked PoC." - }, - { - "name": "The issue has a detailed technical explanation published, that can aid in exploit development", - "description": "The Github issue carefully explains the vulnerability." - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-27103", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "Libde265 v1.0.11 was discovered to contain a heap buffer overflow via the function derive_collocated_motion_vectors at motion.cc.", - "severity": "High", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "issue_id": "XRAY-427848", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-27103", - "https://github.com/strukturag/libde265/issues/394", - "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-47471", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-120" - ], - "cwe_details": { - "CWE-120": { - "name": "Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')", - "description": "The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow." - } - } - } - ], - "summary": "Buffer Overflow vulnerability in strukturag libde265 v1.10.12 allows a local attacker to cause a denial of service via the slice_segment_header function in the slice.cc component.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "issue_id": "XRAY-537162", - "references": [ - "https://github.com/strukturag/libde265/commit/e36b4a1b0bafa53df47514c419d5be3e8916ebc7", - "https://security-tracker.debian.org/tracker/CVE-2023-47471", - "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html", - "https://github.com/strukturag/libde265/issues/426" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-27102", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-476" - ], - "cwe_details": { - "CWE-476": { - "name": "NULL Pointer Dereference", - "description": "A NULL pointer dereference occurs when the application dereferences a pointer that it expects to be valid, but is NULL, typically causing a crash or exit.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "12" - } - ] - } - } - } - ], - "summary": "Libde265 v1.0.11 was discovered to contain a segmentation violation via the function decoder_context::process_slice_segment_header at decctx.cc.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "issue_id": "XRAY-427847", - "references": [ - "https://github.com/strukturag/libde265/issues/393", - "https://security-tracker.debian.org/tracker/CVE-2023-27102", - "https://lists.debian.org/debian-lts-announce/2023/11/msg00032.html" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-49468", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "Libde265 v1.0.14 was discovered to contain a global buffer overflow vulnerability in the read_coding_unit function at slice.cc.", - "severity": "High", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "issue_id": "XRAY-540358", - "references": [ - "https://lists.debian.org/debian-lts-announce/2023/12/msg00022.html", - "https://security-tracker.debian.org/tracker/CVE-2023-49468", - "https://github.com/strukturag/libde265/issues/432" - ], - "extended_information": { - "short_description": "A buffer overflow (in a global variable) in libde265 causes memory corruption leading to DoS and possibly code execution, when parsing attacker-supplied H.265 data.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "The provided PoC demonstrates a crash." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker must be able to provide remote input that will be parsed by H.265, for example - `./dec265 attacker_input`.", - "is_positive": true - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "The impact of this vulnerability depends on the implementation of the vulnerable library. Substantial research has to be conducted to determine the exact impact this vulnerability could have. Code execution is not always achievable through a buffer overflow in a global variable.", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-49467", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "Libde265 v1.0.14 was discovered to contain a heap-buffer-overflow vulnerability in the derive_combined_bipredictive_merging_candidates function at motion.cc.", - "severity": "High", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "issue_id": "XRAY-540357", - "references": [ - "https://github.com/strukturag/libde265/issues/434", - "https://security-tracker.debian.org/tracker/CVE-2023-49467", - "https://lists.debian.org/debian-lts-announce/2023/12/msg00022.html" - ], - "extended_information": { - "short_description": "An infinite loop in libde265 leads to DoS when parsing attacker-supplied H.265 data.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS does not take into account the non-trivial exploitation prerequisites. In addition, the CVSS alludes that remote code execution is possible, while in reality the worst impact of exploiting this issue is denial of service.", - "is_positive": true - }, - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "description": "The attacker must be able to provide remote input that will be parsed by H.265, for example - `./dec265 attacker_input`.", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2024-38949" - } - ], - "summary": "Heap Buffer Overflow vulnerability in Libde265 v1.0.15 allows attackers to crash the application via crafted payload to display444as420 function at sdl.cc", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libde265-0:1.0.11-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libde265-0:1.0.11-1", - "full_path": "libde265-0:1.0.11-1" - } - ] - ] - } - }, - "issue_id": "XRAY-607769", - "references": [ - "https://github.com/strukturag/libde265/issues/460", - "https://github.com/zhangteng0526/CVE-information/blob/main/CVE-2024-38949", - "https://security-tracker.debian.org/tracker/CVE-2024-38949" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-6246", - "cvss_v3_score": "7.8", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "A heap-based buffer overflow was found in the __vsyslog_internal function of the glibc library. This function is called by the syslog and vsyslog functions. This issue occurs when the openlog function was not called, or called with the ident argument set to NULL, and the program name (the basename of argv[0]) is bigger than 1024 bytes, resulting in an application crash or local privilege escalation. This issue affects glibc 2.36 and newer.", - "severity": "High", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-589627", - "references": [ - "https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D2FIH77VHY3KCRROCXOT6L27WMZXSJ2G/", - "https://security.netapp.com/advisory/ntap-20240216-0007/", - "https://security-tracker.debian.org/tracker/CVE-2023-6246", - "https://access.redhat.com/security/cve/CVE-2023-6246", - "http://packetstormsecurity.com/files/176931/glibc-qsort-Out-Of-Bounds-Read-Write.html", - "http://seclists.org/fulldisclosure/2024/Feb/5", - "https://www.openwall.com/lists/oss-security/2024/01/30/6", - "http://packetstormsecurity.com/files/176932/glibc-syslog-Heap-Based-Buffer-Overflow.html", - "https://bugzilla.redhat.com/show_bug.cgi?id=2249053", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MWQ6BZJ6CV5UAW4VZSKJ6TO4KIW2KWAQ/", - "https://security.gentoo.org/glsa/202402-01", - "http://seclists.org/fulldisclosure/2024/Feb/3" - ], - "extended_information": { - "short_description": "A heap buffer overflow in glibc may lead to local privilege escalation.", - "full_description": "[glibc](https://www.gnu.org/software/libc/) is the GNU C Library, a widely-used implementation of the C standard library.\n\nA vulnerability was identified in __vsyslog_internal(), which is called by the API functions `syslog()` and `vsyslog()` of glibc syslog functionality. Unprivileged users could gain full root access by manipulating syslog inputs.\n\nThe initial prerequisite for exploiting this local privilege escalation is a local SUID executable that contains calls to one of the vulnerable functions `syslog()` and `vsyslog()`. In order to exploit this, the attacker needs to control either argv[0], which typically holds the name of the program being executed, or the `openlog()` ident argument. \n\nAs explained in [Qualys’s research](https://qualys.com/2024/01/30/cve-2023-6246/syslog.txt), the identification string (LogTag) being NULL is essential for exploiting this issue. Thus, the `openlog()` function would need to either not be called, or called with NULL for the ident param for successful exploitation. \n\nIn Qualys’s research, they utilized a code path in the `su` program that doesn’t reach `openlog()`. Meaning the default user-controlled, argv[0] was used. Keep in mind another attack vector is possible in a different scenario when the user can control the ident arg of `openlog()`.\n\nSeeing as argv[0] is the name (path) of the running program, it is highly likely for a local attacker to be able to abuse this CVE for a local privilege escalation and unlikely that a remote attacker will have control over this argument for an RCE attack.\n\nQualys demonstrated a successful LPE exploit on Fedora. While no other public exploits are yet known, the threat landscape could evolve. It is likely possible to exploit this on other Linux distributions as well.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has multiple mentions in general media", - "description": "The vulnerability received extensive media coverage." - }, - { - "name": "The issue has a detailed technical explanation published, that can aid in exploit development", - "description": "This vulnerability has a through technical writeup, which also details an exploit." - }, - { - "name": "The prerequisites for exploiting the issue are either extremely common or nonexistent (always exploitable)", - "description": "As explained in the summary, the requirements to trigger the vulnerability are highly likely on default Linux machines that use a vulnerable version of glibc." - }, - { - "name": "The issue can only be exploited by an attacker that can execute code on the vulnerable machine (excluding exceedingly rare circumstances)", - "description": "This vulnerability requires local access to exploit. It is unlikely to be exploitable in remote scenarios as explained in the summary.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "This is a local privilege escalation vulnerability that could enable a local attacker to execute code as a root user." - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2019-9192", - "cvss_v2_score": "5.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-674" - ], - "cwe_details": { - "CWE-674": { - "name": "Uncontrolled Recursion", - "description": "The product does not properly control the amount of recursion that takes place, consuming excessive resources, such as allocated memory or the program stack." - } - } - } - ], - "summary": "In the GNU C Library (aka glibc or libc6) through 2.29, check_dst_limits_calc_pos_1 in posix/regexec.c has Uncontrolled Recursion, as demonstrated by '(|)(\\\\1\\\\1)*' in grep, a different issue than CVE-2018-20796. NOTE: the software maintainer disputes that this is a vulnerability because the behavior occurs only with a crafted pattern", - "severity": "Low", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-75770", - "references": [ - "https://sourceware.org/bugzilla/show_bug.cgi?id=24269", - "https://support.f5.com/csp/article/K26346590?utm_source=f5support\u0026amp%3Butm_medium=RSS", - "https://security-tracker.debian.org/tracker/CVE-2019-9192" - ], - "extended_information": { - "short_description": "Uncontrolled recursion in glibc regexec leads to denial of service.", - "full_description": "The [GNU C Library](https://www.gnu.org/software/libc/), commonly known as glibc, is the GNU Project's implementation of the C standard library.\n\nIn the GNU C Library (aka glibc or libc6) through 2.29, `check_dst_limits_calc_pos_1` in posix/regexec.c has Uncontrolled Recursion, as demonstrated by running grep with the pattern `(|)(\\\\1\\\\1)*`.\n\nNote that in order to exploit this vulnerability, the attacker must control the regular expression **pattern** that glibc uses, unlike standard ReDoS vulnerabilities where only the input buffer needs to be controlled. The The pattern it not likely to be attacker-controlled from remote input.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker must find a remote input that propagates to the `regex` (pattern) argument of `regcomp` and then sent to `regexec`.\nThis includes controlling the pattern argument of a `grep` invocation.", - "is_positive": true - }, - { - "name": "The issue has been disputed by the vendor", - "description": "The software maintainer disputes that this is not a vulnerability because the behavior occurs only with a crafted pattern. Therefore - this issue is unlikely to get a fix.", - "is_positive": true - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "It is highly unlikely that a remote attacker will be able to control a regular expression pattern that's used by glibc", - "is_positive": true - }, - { - "name": "The issue has an exploit published" - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "Denial of service only, marked as unimportant by the Debian tracker", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-6779", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "An off-by-one heap-based buffer overflow was found in the __vsyslog_internal function of the glibc library. This function is called by the syslog and vsyslog functions. This issue occurs when these functions are called with a message bigger than INT_MAX bytes, leading to an incorrect calculation of the buffer size to store the message, resulting in an application crash. This issue affects glibc 2.37 and newer.", - "severity": "High", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-589629", - "references": [ - "http://seclists.org/fulldisclosure/2024/Feb/3", - "https://security.netapp.com/advisory/ntap-20240223-0006/", - "https://access.redhat.com/security/cve/CVE-2023-6779", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D2FIH77VHY3KCRROCXOT6L27WMZXSJ2G/", - "https://security-tracker.debian.org/tracker/CVE-2023-6779", - "https://www.openwall.com/lists/oss-security/2024/01/30/6", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MWQ6BZJ6CV5UAW4VZSKJ6TO4KIW2KWAQ/", - "https://bugzilla.redhat.com/show_bug.cgi?id=2254395", - "https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt", - "https://security.gentoo.org/glsa/202402-01", - "http://packetstormsecurity.com/files/176932/glibc-syslog-Heap-Based-Buffer-Overflow.html" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-6780", - "cvss_v3_score": "5.3", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", - "cwe": [ - "CWE-131" - ], - "cwe_details": { - "CWE-131": { - "name": "Incorrect Calculation of Buffer Size", - "description": "The product does not correctly calculate the size to be used when allocating a buffer, which could lead to a buffer overflow." - } - } - } - ], - "summary": "An integer overflow was found in the __vsyslog_internal function of the glibc library. This function is called by the syslog and vsyslog functions. This issue occurs when these functions are called with a very long message, leading to an incorrect calculation of the buffer size to store the message, resulting in undefined behavior. This issue affects glibc 2.37 and newer.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-589628", - "references": [ - "http://seclists.org/fulldisclosure/2024/Feb/3", - "https://security.gentoo.org/glsa/202402-01", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MWQ6BZJ6CV5UAW4VZSKJ6TO4KIW2KWAQ/", - "https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/D2FIH77VHY3KCRROCXOT6L27WMZXSJ2G/", - "http://packetstormsecurity.com/files/176932/glibc-syslog-Heap-Based-Buffer-Overflow.html", - "https://www.openwall.com/lists/oss-security/2024/01/30/6", - "https://access.redhat.com/security/cve/CVE-2023-6780", - "https://security-tracker.debian.org/tracker/CVE-2023-6780", - "https://bugzilla.redhat.com/show_bug.cgi?id=2254396" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-33601" - } - ], - "summary": "nscd: netgroup cache may terminate daemon on memory allocation failure\n\nThe Name Service Cache Daemon's (nscd) netgroup cache uses xmalloc or\nxrealloc and these functions may terminate the process due to a memory\nallocation failure resulting in a denial of service to the clients. The\nflaw was introduced in glibc 2.15 when the cache was added to nscd.\n\nThis vulnerability is only present in the nscd binary.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-599389", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-33601", - "https://sourceware.org/git/?p=glibc.git;a=blob;f=advisories/GLIBC-SA-2024-0007", - "https://lists.debian.org/debian-lts-announce/2024/06/msg00026.html", - "http://www.openwall.com/lists/oss-security/2024/07/22/5", - "https://security.netapp.com/advisory/ntap-20240524-0014/" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-33599" - } - ], - "summary": "nscd: Stack-based buffer overflow in netgroup cache\n\nIf the Name Service Cache Daemon's (nscd) fixed size cache is exhausted\nby client requests then a subsequent client request for netgroup data\nmay result in a stack-based buffer overflow. This flaw was introduced\nin glibc 2.15 when the cache was added to nscd.\n\nThis vulnerability is only present in the nscd binary.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-599387", - "references": [ - "http://www.openwall.com/lists/oss-security/2024/07/22/5", - "https://security-tracker.debian.org/tracker/CVE-2024-33599", - "https://lists.debian.org/debian-lts-announce/2024/06/msg00026.html", - "https://security.netapp.com/advisory/ntap-20240524-0011/", - "https://sourceware.org/git/?p=glibc.git;a=blob;f=advisories/GLIBC-SA-2024-0005" - ], - "extended_information": { - "short_description": "A stack buffer overflow in the Name Service Cache Daemon (NSCD) in the GNU C library may lead to remote code execution.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "No PoC and no technical writeup were published.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The `/etc/nscd.conf` configuration file does not support netgroup caching by default.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Potential remote code execution." - }, - { - "name": "The issue can be exploited by attackers over the network", - "description": "The Name Service Cache Daemon accepts arbitrary network input." - } - ], - "remediation": "##### Deployment mitigations\n\nDisable netgroup caching in the NSCD configuration.\nRemove the following line from `/etc/nscd.conf` -\n```\nenable-cache netgroup yes\n```" - } - }, - { - "cves": [ - { - "cve": "CVE-2019-1010022", - "cvss_v2_score": "7.5", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P", - "cvss_v3_score": "9.8", - "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-119" - ], - "cwe_details": { - "CWE-119": { - "name": "Improper Restriction of Operations within the Bounds of a Memory Buffer", - "description": "The product performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "17" - } - ] - } - } - } - ], - "summary": "GNU Libc current is affected by: Mitigation bypass. The impact is: Attacker may bypass stack guard protection. The component is: nptl. The attack vector is: Exploit stack buffer overflow vulnerability and use this bypass vulnerability to bypass stack guard. NOTE: Upstream comments indicate \"this is being treated as a non-security bug and no real threat.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-84860", - "references": [ - "https://sourceware.org/bugzilla/show_bug.cgi?id=22850#c3", - "https://security-tracker.debian.org/tracker/CVE-2019-1010022", - "https://ubuntu.com/security/CVE-2019-1010022", - "https://sourceware.org/bugzilla/show_bug.cgi?id=22850" - ], - "extended_information": { - "short_description": "Insufficient mitigation implementation in glibc's pthread could lead to an attacker bypassing the stack protector/canary mitigation.", - "full_description": "The [GNU C Library](https://www.gnu.org/s/libc/), commonly known as glibc, is the GNU Project's implementation of the C standard library.\n\nA well-known issue leads to the fact that in applications that call `pthread_create()`, if a large stack buffer overflow occurs, the stack overflow may overwrite both the reference value of the stack canary and the canary that's saved inside the stack-frame. This leads to a complete bypass of the \"stack protector\" mitigation.\n\nSpecifically, The stack protector (\"canary\") should protect an application from been exploited by stack-based buffer overflows. It is placed on stack frame in function prologue and checked with some trusted value in the function epilogue.\n\nFor x86 and x86-64 architecture the canary value is located in structure `tcbhead_t` field `stack_guard`. A Special register ('gs' for i386 and 'fs' for x86-64) keeps a pointer to this structure. The value `tcbhead_t.stack_guard` is compared with one on the stack to detect stack smashing.\n\nNPTL (Native POSIX Threads Library) is the GNU C library POSIX threads implementation that is used on modern Linux systems. When a `pthread` (new thread) is created, it will keep the `tcphead_t` structure in the thread stack. Thus, an attacker can overwrite the \"reference\" stack-canary value (since it's saved on the stack) by means of stack overflow in a new thread.\n\nThis vulnerability was disputed by the libc maintainers, since it is a well-known issue and not a standalone vulnerability but rather a vulnerability in a mitigation mechanism.", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "The PoC demonstrates changing the \"retained\" stack-canary value" - }, - { - "name": "The issue cannot be exploited on its own, and can only be used as part of an attack chain", - "description": "Exploitation of this issue requires exploiting a different stack-buffer-overflow vulnerability in the target application", - "is_positive": true - }, - { - "name": "The issue has been disputed by the vendor", - "description": "The Libc maintainers treat this issue as a non-security bug, since it is a vulnerability in a post-attack mitigation (not a standalone vulnerability)", - "is_positive": true - }, - { - "name": "The issue has a detailed technical explanation published, that can aid in exploit development" - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The victim application must call `pthread_create()` and must be vulnerable to a stack-buffer-overflow type of vulnerability", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2024-33602" - } - ], - "summary": "nscd: netgroup cache assumes NSS callback uses in-buffer strings\n\nThe Name Service Cache Daemon's (nscd) netgroup cache can corrupt memory\nwhen the NSS callback does not store all strings in the provided buffer.\nThe flaw was introduced in glibc 2.15 when the cache was added to nscd.\n\nThis vulnerability is only present in the nscd binary.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-599390", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-33602", - "http://www.openwall.com/lists/oss-security/2024/07/22/5", - "https://sourceware.org/git/?p=glibc.git;a=blob;f=advisories/GLIBC-SA-2024-0008", - "https://security.netapp.com/advisory/ntap-20240524-0012/", - "https://lists.debian.org/debian-lts-announce/2024/06/msg00026.html" - ] - }, - { - "cves": [ - { - "cve": "CVE-2019-1010025", - "cvss_v2_score": "5.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:N/A:N", - "cvss_v3_score": "5.3", - "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", - "cwe": [ - "CWE-330" - ], - "cwe_details": { - "CWE-330": { - "name": "Use of Insufficiently Random Values", - "description": "The product uses insufficiently random numbers or values in a security context that depends on unpredictable numbers." - } - } - } - ], - "summary": "GNU Libc current is affected by: Mitigation bypass. The impact is: Attacker may guess the heap addresses of pthread_created thread. The component is: glibc. NOTE: the vendor's position is \"ASLR bypass itself is not a vulnerability.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-84867", - "references": [ - "https://sourceware.org/bugzilla/show_bug.cgi?id=22853", - "https://support.f5.com/csp/article/K06046097", - "https://ubuntu.com/security/CVE-2019-1010025", - "https://support.f5.com/csp/article/K06046097?utm_source=f5support\u0026amp%3Butm_medium=RSS", - "https://security-tracker.debian.org/tracker/CVE-2019-1010025" - ] - }, - { - "cves": [ - { - "cve": "CVE-2019-1010023", - "cvss_v2_score": "6.8", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:P/I:P/A:P", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "cwe": [ - "NVD-CWE-noinfo" - ] - } - ], - "summary": "GNU Libc current is affected by: Re-mapping current loaded library with malicious ELF file. The impact is: In worst case attacker may evaluate privileges. The component is: libld. The attack vector is: Attacker sends 2 ELF files to victim and asks to run ldd on it. ldd execute code. NOTE: Upstream comments indicate \"this is being treated as a non-security bug and no real threat.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-84853", - "references": [ - "http://www.securityfocus.com/bid/109167", - "https://support.f5.com/csp/article/K11932200?utm_source=f5support\u0026amp%3Butm_medium=RSS", - "https://security-tracker.debian.org/tracker/CVE-2019-1010023", - "https://sourceware.org/bugzilla/show_bug.cgi?id=22851", - "https://ubuntu.com/security/CVE-2019-1010023" - ] - }, - { - "cves": [ - { - "cve": "CVE-2018-20796", - "cvss_v2_score": "5.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:P", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-674" - ], - "cwe_details": { - "CWE-674": { - "name": "Uncontrolled Recursion", - "description": "The product does not properly control the amount of recursion that takes place, consuming excessive resources, such as allocated memory or the program stack." - } - } - } - ], - "summary": "In the GNU C Library (aka glibc or libc6) through 2.29, check_dst_limits_calc_pos_1 in posix/regexec.c has Uncontrolled Recursion, as demonstrated by '(\\227|)(\\\\1\\\\1|t1|\\\\\\2537)+' in grep.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-75786", - "references": [ - "https://security.netapp.com/advisory/ntap-20190315-0002/", - "https://lists.gnu.org/archive/html/bug-gnulib/2019-01/msg00108.html", - "http://www.securityfocus.com/bid/107160", - "https://security-tracker.debian.org/tracker/CVE-2018-20796", - "https://support.f5.com/csp/article/K26346590?utm_source=f5support\u0026amp%3Butm_medium=RSS", - "https://debbugs.gnu.org/cgi/bugreport.cgi?bug=34141" - ], - "extended_information": { - "short_description": "An uncontrolled recursion in glibc may result in a denial of service via malformed regular expression.", - "full_description": "The [GNU C Library](https://www.gnu.org/software/libc/), commonly known as glibc, is the GNU Project's implementation of the C standard library.\n\nAn uncontrolled recursion vulnerability exists in glibc's regular expression parsing engine (posix/regexec.c).\n\nAn attacker can exploit this issue by invoking any tool (`grep`, `sed` etc.) or API (`regexec()`) with a crafted regular expression. This can be demonstrated by the crafted input: `(\\227|)(\\\\1\\\\1|t1|\\\\\\2537)+'`.\nThis scenario is much more likely in a local attack than a remote one.\n\nNote that in order to exploit this vulnerability, the attacker must control the regular expression **pattern** that glibc uses, unlike standard ReDoS vulnerabilities where only the input buffer needs to be controlled. The The pattern it not likely to be attacker-controlled from remote input.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has been disputed by the vendor", - "description": "The software maintainer disputes that this is not a vulnerability because the behavior occurs only with a crafted pattern. Therefore - this issue is unlikely to get a fix.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker must find a remote input that propagates to the `regex` (pattern) argument of `regcomp` and then sent to `regexec`.\nThis includes controlling the pattern argument of a `grep` invocation.", - "is_positive": true - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "It is highly unlikely that a remote attacker will be able to control a regular expression pattern that's used by glibc", - "is_positive": true - }, - { - "name": "The issue has an exploit published" - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "Denial of service only, marked as unimportant by the Debian tracker", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2010-4756", - "cvss_v2_score": "4.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:S/C:N/I:N/A:P", - "cwe": [ - "CWE-399" - ] - } - ], - "summary": "The glob implementation in the GNU C Library (aka glibc or libc6) allows remote authenticated users to cause a denial of service (CPU and memory consumption) via crafted glob expressions that do not match any pathnames, as demonstrated by glob expressions in STAT commands to an FTP daemon, a different vulnerability than CVE-2010-2632.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-33571", - "references": [ - "http://securityreason.com/achievement_securityalert/89", - "https://security-tracker.debian.org/tracker/CVE-2010-4756", - "https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2010-4756", - "http://cxib.net/stuff/glob-0day.c", - "https://bugzilla.redhat.com/show_bug.cgi?id=681681", - "http://securityreason.com/exploitalert/9223" - ], - "extended_information": { - "short_description": "An unbounded computation in glibc leads to denial of service when parsing crafted glob expressions.", - "full_description": "The GNU C Library project provides the core libraries for the GNU system and GNU/Linux systems, as well as many other systems that use Linux as the kernel. One of the provided functions is `glob`. *This function expands a filename wildcard which is passed as pattern*. It usually implements a limitation though the `GLOB_LIMIT` constant but a flaw is causing a `denial of service when the crafted glob expression does not match any pathnames`.\nThis vulnerability is very similar to the one affecting the *STAT* commands against an FTP Deamon which gives information about the file and the filesystem, also vulnerable to glob expression causing the process to use 100% of the CPU capabilities for a long time.\nHowever, this vulnerability needs the attacker to be an authenticated user.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "It is unlikely that a remote attacker will be able to control a glob pattern from a remote input", - "is_positive": true - }, - { - "name": "The issue has been disputed by the vendor", - "description": "The software maintainer disputes that this is not a vulnerability because the behavior occurs only with a crafted glob pattern. Therefore - this issue is unlikely to get a fix.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker must find a remote input that propagates into the `pattern` argument of a `glob` call.\nHowever, as the technical [write-up](https://cxsecurity.com/issue/WLB-2010100135) shows, this vulnerability can be remotely exploited in some common cases, such as FTP servers.", - "is_positive": true - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "Marked as unimportant by the Debian tracker. Computation-based DoS.", - "is_positive": true - }, - { - "name": "The issue has a detailed technical explanation published, that can aid in exploit development", - "description": "A technical [write-up](https://cxsecurity.com/issue/WLB-2010100135) was published explaining the bug and how to trigger it." - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2019-1010024", - "cvss_v2_score": "5.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:N/A:N", - "cvss_v3_score": "5.3", - "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", - "cwe": [ - "CWE-200" - ], - "cwe_details": { - "CWE-200": { - "name": "Exposure of Sensitive Information to an Unauthorized Actor", - "description": "The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information." - } - } - } - ], - "summary": "GNU Libc current is affected by: Mitigation bypass. The impact is: Attacker may bypass ASLR using cache of thread stack and heap. The component is: glibc. NOTE: Upstream comments indicate \"this is being treated as a non-security bug and no real threat.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-84852", - "references": [ - "https://ubuntu.com/security/CVE-2019-1010024", - "https://support.f5.com/csp/article/K06046097?utm_source=f5support\u0026amp%3Butm_medium=RSS", - "https://security-tracker.debian.org/tracker/CVE-2019-1010024", - "https://sourceware.org/bugzilla/show_bug.cgi?id=22852", - "http://www.securityfocus.com/bid/109162", - "https://support.f5.com/csp/article/K06046097" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-33600" - } - ], - "summary": "nscd: Null pointer crashes after notfound response\n\nIf the Name Service Cache Daemon's (nscd) cache fails to add a not-found\nnetgroup response to the cache, the client request can result in a null\npointer dereference. This flaw was introduced in glibc 2.15 when the\ncache was added to nscd.\n\nThis vulnerability is only present in the nscd binary.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-599388", - "references": [ - "https://security.netapp.com/advisory/ntap-20240524-0013/", - "https://security-tracker.debian.org/tracker/CVE-2024-33600", - "https://lists.debian.org/debian-lts-announce/2024/06/msg00026.html", - "https://sourceware.org/git/?p=glibc.git;a=blob;f=advisories/GLIBC-SA-2024-0006", - "http://www.openwall.com/lists/oss-security/2024/07/22/5" - ], - "extended_information": { - "short_description": "A null pointer dereference in the Name Service Cache Daemon (NSCD) in the GNU C library may lead to denial of service.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "No PoC and no technical writeup were published.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The `/etc/nscd.conf` configuration file does not support netgroup caching by default.", - "is_positive": true - }, - { - "name": "The issue can be exploited by attackers over the network", - "description": "The Name Service Cache Daemon accepts arbitrary network input" - } - ], - "remediation": "##### Deployment mitigations\n\nDisable netgroup caching in the NSCD configuration.\nRemove the following line from `/etc/nscd.conf` -\n```\nenable-cache netgroup yes\n```" - } - }, - { - "cves": [ - { - "cve": "CVE-2024-2961" - } - ], - "summary": "The iconv() function in the GNU C Library versions 2.39 and older may overflow the output buffer passed to it by up to 4 bytes when converting strings to the ISO-2022-CN-EXT character set, which may be used to crash an application or overwrite a neighbouring variable.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libc-bin:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc-bin:2.36-9+deb12u3", - "full_path": "libc-bin:2.36-9+deb12u3" - } - ] - ] - }, - "deb://debian:bookworm:libc6:2.36-9+deb12u3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libc6:2.36-9+deb12u3", - "full_path": "libc6:2.36-9+deb12u3" - } - ] - ] - } - }, - "issue_id": "XRAY-598749", - "references": [ - "https://lists.debian.org/debian-lts-announce/2024/05/msg00001.html", - "http://www.openwall.com/lists/oss-security/2024/07/22/5", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/YAMJQI3Y6BHWV3CUTYBXOZONCUJNOB2Z/", - "http://www.openwall.com/lists/oss-security/2024/04/24/2", - "https://security.netapp.com/advisory/ntap-20240531-0002/", - "http://www.openwall.com/lists/oss-security/2024/05/27/1", - "http://www.openwall.com/lists/oss-security/2024/05/27/3", - "https://sourceware.org/git/?p=glibc.git;a=blob;f=advisories/GLIBC-SA-2024-0004", - "http://www.openwall.com/lists/oss-security/2024/04/17/9", - "http://www.openwall.com/lists/oss-security/2024/05/27/5", - "http://www.openwall.com/lists/oss-security/2024/05/27/2", - "http://www.openwall.com/lists/oss-security/2024/05/27/4", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/BTJFBGHDYG5PEIFD5WSSSKSFZ2AZWC5N/", - "https://security-tracker.debian.org/tracker/CVE-2024-2961", - "http://www.openwall.com/lists/oss-security/2024/05/27/6", - "http://www.openwall.com/lists/oss-security/2024/04/18/4", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/P3I4KYS6EU6S7QZ47WFNTPVAHFIUQNEL/" - ], - "extended_information": { - "short_description": "An out-of-bound write vulnerability in Glibc can lead to denial of service when using a specific character set.", - "full_description": "[Glibc](https://www.gnu.org/software/libc/) is a library that provides core libraries with API functions.\n\n`ISO-2022-CN` is a 7-bit Chinese character encoding that supports simplified and traditional Chinese characters. `ISO-2022-CN-EXT` is an extension of `ISO-2022-CN` that supports other GB character sets.\n\nThe vulnerability was introduced in the GNU C Library versions 2.39 in the `iconv()` function.\nAttackers can use the out-of-bounds write vulnerability by overflowing the buffer passed to the `iconv()` function and potentially overwriting the neighboring variables or crashing the application.\n`SS2designation` and `SS3designation` do not perform the necessary boundary checks, allowing attackers to overflow of 1, 2, or 3 bytes with fixed values by converting the following strings to the `ISO-2022-CN-EXT` character set: '$+I', '$+J', '$+K', '$+L', '$+M', or '$*H'.\n\nThe researcher who found the vulnerability mentioned that it is not likely to be exploited in most libraries and programs except for PHP which was found to be applicable.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The researcher who found the vulnerability mentioned that it is not likely to be exploited in most libraries and programs except for PHP which was found to be applicable.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "This issue can lead to a Denial of Service." - }, - { - "name": "The issue has multiple mentions in general media", - "description": "The vulnerability was discussed at the OffensiveCon conference." - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-49460", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "cwe": [ - "NVD-CWE-noinfo" - ] - } - ], - "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the function UncompressedImageCodec::decode_uncompressed_image.", - "severity": "High", - "components": { - "deb://debian:bookworm:libheif1:1.15.1-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", - "full_path": "libheif1:1.15.1-1" - } - ] - ] - } - }, - "issue_id": "XRAY-540353", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2023-49460", - "https://github.com/strukturag/libheif/issues/1046" - ], - "extended_information": { - "short_description": "A NULL pointer dereference in libheif may lead to denial of service when parsing crafted images.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "A proof-of-concept was published in the report's GitHub Issue." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "To successfully exploit this vulnerability an attacker needs to find a way to propagate input into the vulnerable `UncompressedImageCodec::decode_uncompressed_image` function.", - "is_positive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS score does not reflect the context dependent exploitation and impact of this vulnerability.", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-49463", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "cwe": [ - "NVD-CWE-noinfo" - ] - } - ], - "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the function find_exif_tag at /libheif/exif.cc.", - "severity": "High", - "components": { - "deb://debian:bookworm:libheif1:1.15.1-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", - "full_path": "libheif1:1.15.1-1" - } - ] - ] - } - }, - "issue_id": "XRAY-540355", - "references": [ - "https://github.com/strukturag/libheif/issues/1042", - "https://github.com/strukturag/libheif", - "https://security-tracker.debian.org/tracker/CVE-2023-49463" - ], - "extended_information": { - "short_description": "An integer overflow in libheif leads to denial of service.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS score does not reflect the context dependent exploitation of this vulnerability.", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "A proof-of-concept was published along with the vulnerability via (GitHub)[https://github.com/strukturag/libheif/issues/1042]." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "To successfully exploit this vulnerability an attacker needs to find a way to propagate input into the vulnerable functions `modify_exif_tag_if_it_exists(unsigned char*, unsigned int, unsigned short, unsigned short)` or `read_exif_orientation_tag(unsigned char const*, unsigned int)`.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Successful exploitation of this vulnerability leads to denial of service." - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-29659", - "cvss_v3_score": "6.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-369" - ], - "cwe_details": { - "CWE-369": { - "name": "Divide By Zero", - "description": "The product divides a value by zero." - } - } - } - ], - "summary": "A Segmentation fault caused by a floating point exception exists in libheif 1.15.1 using crafted heif images via the heif::Fraction::round() function in box.cc, which causes a denial of service.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libheif1:1.15.1-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", - "full_path": "libheif1:1.15.1-1" - } - ] - ] - } - }, - "issue_id": "XRAY-519184", - "references": [ - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/CKAE6NQBA3Q7GS6VTNDZRZZZVPPEFUEZ/", - "https://github.com/strukturag/libheif/issues/794", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LGKHDCS4HRZE3UGXYYDYPTIPNIBRLQ5L/", - "https://security-tracker.debian.org/tracker/CVE-2023-29659" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-25269" - } - ], - "summary": "libheif \u003c= 1.17.6 contains a memory leak in the function JpegEncoder::Encode. This flaw allows an attacker to cause a denial of service attack.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libheif1:1.15.1-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", - "full_path": "libheif1:1.15.1-1" - } - ] - ] - } - }, - "issue_id": "XRAY-593085", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-25269", - "https://github.com/strukturag/libheif/issues/1073" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-49464", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "cwe": [ - "NVD-CWE-noinfo" - ] - } - ], - "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the function UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci.", - "severity": "High", - "components": { - "deb://debian:bookworm:libheif1:1.15.1-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", - "full_path": "libheif1:1.15.1-1" - } - ] - ] - } - }, - "issue_id": "XRAY-540356", - "references": [ - "https://github.com/strukturag/libheif/issues/1044", - "https://security-tracker.debian.org/tracker/CVE-2023-49464" - ], - "extended_information": { - "short_description": "A use-after-free in libheif leads to denial of service and possibly remote code execution.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS score given to this CVE does not take into account the unlikely prerequisites for applicability of this vulnerability and the context required to exploit it.", - "is_positive": true - }, - { - "name": "The issue has an exploit published", - "description": "The fixing PR contains a denial of service PoC" - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "An attacker needs to find a remote input that propagates into the function `UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci`.", - "is_positive": true - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "For this vulnerability to be applicable, `libheif1` needs to be compiled with the flag `-DWITH_UNCOMPRESSED_CODEC=ON`.\n\nWe found that this setting is enabled only in some package managers by default, but not all of them. In vanilla compilations, this flag is disabled by default.", - "is_positive": true - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Exploitation requires triggering a use-after-free beyond the scope of a single function. The use-after-free has not been proven to be able to cause code execution.", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-49462", - "cvss_v3_score": "8.8", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "cwe": [ - "NVD-CWE-noinfo" - ] - } - ], - "summary": "libheif v1.17.5 was discovered to contain a segmentation violation via the component /libheif/exif.cc.", - "severity": "High", - "components": { - "deb://debian:bookworm:libheif1:1.15.1-1": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libheif1:1.15.1-1", - "full_path": "libheif1:1.15.1-1" - } - ] - ] - } - }, - "issue_id": "XRAY-540354", - "references": [ - "https://github.com/strukturag/libheif/issues/1043", - "https://security-tracker.debian.org/tracker/CVE-2023-49462" - ], - "extended_information": { - "short_description": "An integer overflow in libheif leads to denial of service.", - "jfrog_research_severity": "Medium", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "A proof-of-concept was published along with the vulnerability via (GitHub)[https://github.com/strukturag/libheif/issues/1043]." - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS score does not reflect the context dependent exploitation of this vulnerability.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "To successfully exploit this vulnerability an attacker needs to find a way to propagate input into the vulnerable functions `modify_exif_tag_if_it_exists(unsigned char*, unsigned int, unsigned short, unsigned short)` or `read_exif_orientation_tag(unsigned char const*, unsigned int)`.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Successful exploitation of this vulnerability leads to denial of service." - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2018-6829", - "cvss_v2_score": "5.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:N/A:N", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", - "cwe": [ - "CWE-327" - ], - "cwe_details": { - "CWE-327": { - "name": "Use of a Broken or Risky Cryptographic Algorithm", - "description": "The product uses a broken or risky cryptographic algorithm or protocol." - } - } - } - ], - "summary": "cipher/elgamal.c in Libgcrypt through 1.8.2, when used to encrypt messages directly, improperly encodes plaintexts, which allows attackers to obtain sensitive information by reading ciphertext data (i.e., it does not have semantic security in face of a ciphertext-only attack). The Decisional Diffie-Hellman (DDH) assumption does not hold for Libgcrypt's ElGamal implementation.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libgcrypt20:1.10.1-3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libgcrypt20:1.10.1-3", - "full_path": "libgcrypt20:1.10.1-3" - } - ] - ] - } - }, - "issue_id": "XRAY-65914", - "references": [ - "https://github.com/weikengchen/attack-on-libgcrypt-elgamal/wiki", - "https://security-tracker.debian.org/tracker/CVE-2018-6829", - "https://lists.gnupg.org/pipermail/gcrypt-devel/2018-February/004394.html", - "https://www.oracle.com/security-alerts/cpujan2020.html", - "https://github.com/weikengchen/attack-on-libgcrypt-elgamal" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-2236", - "cwe": [ - "CWE-208" - ], - "cwe_details": { - "CWE-208": { - "name": "Observable Timing Discrepancy", - "description": "Two separate operations in a product require different amounts of time to complete, in a way that is observable to an actor and reveals security-relevant information about the state of the product, such as whether a particular operation was successful or not." - } - } - } - ], - "summary": "A timing-based side-channel flaw was found in libgcrypt's RSA implementation. This issue may allow a remote attacker to initiate a Bleichenbacher-style attack, which can lead to the decryption of RSA ciphertexts.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libgcrypt20:1.10.1-3": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libgcrypt20:1.10.1-3", - "full_path": "libgcrypt20:1.10.1-3" - } - ] - ] - } - }, - "issue_id": "XRAY-593361", - "references": [ - "https://bugzilla.redhat.com/show_bug.cgi?id=2268268", - "https://bugzilla.redhat.com/show_bug.cgi?id=2245218", - "https://security-tracker.debian.org/tracker/CVE-2024-2236", - "https://access.redhat.com/security/cve/CVE-2024-2236" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-0553", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", - "cwe": [ - "CWE-203" - ], - "cwe_details": { - "CWE-203": { - "name": "Observable Discrepancy", - "description": "The product behaves differently or sends different responses under different circumstances in a way that is observable to an unauthorized actor, which exposes security-relevant information about the state of the product, such as whether a particular operation was successful or not." - } - } - } - ], - "summary": "A vulnerability was found in GnuTLS. The response times to malformed ciphertexts in RSA-PSK ClientKeyExchange differ from the response times of ciphertexts with correct PKCS#1 v1.5 padding. This issue may allow a remote attacker to perform a timing side-channel attack in the RSA-PSK key exchange, potentially leading to the leakage of sensitive data. CVE-2024-0553 is designated as an incomplete resolution for CVE-2023-5981.", - "severity": "High", - "components": { - "deb://debian:bookworm:libgnutls30:3.7.9-2": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", - "full_path": "libgnutls30:3.7.9-2" - } - ] - ] - } - }, - "issue_id": "XRAY-588549", - "references": [ - "https://access.redhat.com/errata/RHSA-2024:2094", - "https://access.redhat.com/errata/RHSA-2024:0627", - "https://gitlab.com/gnutls/gnutls/-/issues/1522", - "https://access.redhat.com/errata/RHSA-2024:1383", - "https://access.redhat.com/errata/RHSA-2024:0796", - "http://www.openwall.com/lists/oss-security/2024/01/19/3", - "https://security.netapp.com/advisory/ntap-20240202-0011/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNXKVR5YNUEBNHAHM5GSYKBZX4W2HMN2/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/7ZEIOLORQ7N6WRPFXZSYDL2MC4LP7VFV/", - "https://lists.gnupg.org/pipermail/gnutls-help/2024-January/004841.html", - "https://access.redhat.com/errata/RHSA-2024:1108", - "https://lists.debian.org/debian-lts-announce/2024/02/msg00010.html", - "https://access.redhat.com/security/cve/CVE-2024-0553", - "https://access.redhat.com/errata/RHSA-2024:0533", - "https://access.redhat.com/errata/RHSA-2024:1082", - "https://bugzilla.redhat.com/show_bug.cgi?id=2258412", - "https://security-tracker.debian.org/tracker/CVE-2024-0553" - ], - "extended_information": { - "short_description": "A design problem in GnuTLS may lead to RSA key brute force when attackers can cause many decryption operations.", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue can be exploited by attackers over the network", - "description": "This vulnerability does not rely on timing to exploit, but rather on the server informing the client that decryption failed, hence it can be exploited remotely, completely disregarding latency issues." - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The given CVSS score does not take the context required to exploit the vulnerability into account.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "This CVE is only exploitable when all of the following conditions are met:\n\n1. The server must use `RSA` for key exchange.\n2. The server encrypts/decrypts `RSA` with `PKCS#1 v1.5` padding.\n3. The server informs the client when decryption fails.\n4. An attacker is on the same subnet, hijacks a session between the client and the server and manipulates the client data.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "A successful attack would compromise the server's private RSA key, allowing the attacker to decrypt any sniffed TLS traffic sent to or from the server from any host." - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Although Bleichenbacher's Attack is well documented today, a high technical understanding of cryptography is required to exploit it.", - "is_positive": true - } - ], - "remediation": "##### Development mitigations\n\n- When choosing a key exchange for your server, avoid using `RSA` and instead opt for the `Diffie-Hellman` key exchange, which provides forward secrecy.\nThis can be done by generating an ECDH key using OpenSSL:\n`openssl ecparam -name prime256v1 -genkey -noout -out mykey-prime256v1.pem`\nAnd giving the filepath of the keyfile to the `gnutls_certificate_set_x509_key_file` function - \n```c\ngnutls_certificate_set_x509_key_file(res, certfile, \"mykey-prime256v1.pem\", GNUTLS_X509_FMT_PEM);\n```\n\n- When using `RSA` for key exchange, use the `OAEP` padding scheme instead of `PKCS#1 v1.5`.\n\n- When using `RSA` and `PKCS#1` for key exchange, avoid informing the client of decryption failure." - } - }, - { - "cves": [ - { - "cve": "CVE-2024-28834", - "cwe": [ - "CWE-200" - ], - "cwe_details": { - "CWE-200": { - "name": "Exposure of Sensitive Information to an Unauthorized Actor", - "description": "The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information." - } - } - } - ], - "summary": "A flaw was found in GnuTLS. The Minerva attack is a cryptographic vulnerability that exploits deterministic behavior in systems like GnuTLS, leading to side-channel leaks. In specific scenarios, such as when using the GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE flag, it can result in a noticeable step in nonce size from 513 to 512 bits, exposing a potential timing side-channel.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libgnutls30:3.7.9-2": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", - "full_path": "libgnutls30:3.7.9-2" - } - ] - ] - } - }, - "issue_id": "XRAY-594374", - "references": [ - "https://access.redhat.com/errata/RHSA-2024:1784", - "https://access.redhat.com/errata/RHSA-2024:2044", - "https://access.redhat.com/security/cve/CVE-2024-28834", - "http://www.openwall.com/lists/oss-security/2024/03/22/1", - "https://access.redhat.com/errata/RHSA-2024:1997", - "https://lists.gnupg.org/pipermail/gnutls-help/2024-March/004845.html", - "https://access.redhat.com/errata/RHSA-2024:2570", - "https://security-tracker.debian.org/tracker/CVE-2024-28834", - "http://www.openwall.com/lists/oss-security/2024/03/22/2", - "https://access.redhat.com/errata/RHSA-2024:1879", - "https://security.netapp.com/advisory/ntap-20240524-0004/", - "https://bugzilla.redhat.com/show_bug.cgi?id=2269228", - "https://access.redhat.com/errata/RHSA-2024:2889", - "https://minerva.crocs.fi.muni.cz/", - "https://people.redhat.com/~hkario/marvin/" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-28835", - "cwe": [ - "CWE-248" - ], - "cwe_details": { - "CWE-248": { - "name": "Uncaught Exception", - "description": "An exception is thrown from a function, but it is not caught." - } - } - } - ], - "summary": "A flaw has been discovered in GnuTLS where an application crash can be induced when attempting to verify a specially crafted .pem bundle using the \"certtool --verify-chain\" command.", - "severity": "Unknown", - "components": { - "deb://debian:bookworm:libgnutls30:3.7.9-2": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", - "full_path": "libgnutls30:3.7.9-2" - } - ] - ] - } - }, - "issue_id": "XRAY-594364", - "references": [ - "http://www.openwall.com/lists/oss-security/2024/03/22/2", - "https://bugzilla.redhat.com/show_bug.cgi?id=2269084", - "https://access.redhat.com/errata/RHSA-2024:2570", - "https://lists.gnupg.org/pipermail/gnutls-help/2024-March/004845.html", - "https://security-tracker.debian.org/tracker/CVE-2024-28835", - "https://access.redhat.com/errata/RHSA-2024:2889", - "https://access.redhat.com/security/cve/CVE-2024-28835", - "https://access.redhat.com/errata/RHSA-2024:1879", - "http://www.openwall.com/lists/oss-security/2024/03/22/1" - ] - }, - { - "cves": [ - { - "cve": "CVE-2011-3389", - "cvss_v2_score": "4.3", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:P/I:N/A:N", - "cwe": [ - "CWE-326" - ], - "cwe_details": { - "CWE-326": { - "name": "Inadequate Encryption Strength", - "description": "The product stores or transmits sensitive data using an encryption scheme that is theoretically sound, but is not strong enough for the level of protection required." - } - } - } - ], - "summary": "The SSL protocol, as used in certain configurations in Microsoft Windows and Microsoft Internet Explorer, Mozilla Firefox, Google Chrome, Opera, and other products, encrypts data by using CBC mode with chained initialization vectors, which allows man-in-the-middle attackers to obtain plaintext HTTP headers via a blockwise chosen-boundary attack (BCBA) on an HTTPS session, in conjunction with JavaScript code that uses (1) the HTML5 WebSocket API, (2) the Java URLConnection API, or (3) the Silverlight WebClient API, aka a \"BEAST\" attack.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libgnutls30:3.7.9-2": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", - "full_path": "libgnutls30:3.7.9-2" - } - ] - ] - } - }, - "issue_id": "XRAY-42166", - "references": [ - "http://www.opera.com/docs/changelogs/mac/1160/", - "http://www.securityfocus.com/bid/49388", - "http://secunia.com/advisories/55322", - "http://support.apple.com/kb/HT5501", - "http://my.opera.com/securitygroup/blog/2011/09/28/the-beast-ssl-tls-issue", - "http://www.redhat.com/support/errata/RHSA-2012-0006.html", - "http://secunia.com/advisories/48256", - "http://www.opera.com/docs/changelogs/unix/1160/", - "http://marc.info/?l=bugtraq\u0026m=133365109612558\u0026w=2", - "http://technet.microsoft.com/security/advisory/2588513", - "http://marc.info/?l=bugtraq\u0026m=133728004526190\u0026w=2", - "http://secunia.com/advisories/45791", - "https://cert-portal.siemens.com/productcert/pdf/ssa-556833.pdf", - "http://www.securitytracker.com/id?1026704", - "http://support.apple.com/kb/HT5130", - "https://hermes.opensuse.org/messages/13155432", - "http://vnhacker.blogspot.com/2011/09/beast.html", - "http://downloads.asterisk.org/pub/security/AST-2016-001.html", - "https://bugzilla.redhat.com/show_bug.cgi?id=737506", - "http://lists.apple.com/archives/security-announce/2012/May/msg00001.html", - "http://www.opera.com/docs/changelogs/unix/1151/", - "http://secunia.com/advisories/48948", - "http://support.apple.com/kb/HT5001", - "https://blogs.oracle.com/sunsecurity/entry/multiple_vulnerabilities_in_fetchmail", - "http://support.apple.com/kb/HT4999", - "http://www.us-cert.gov/cas/techalerts/TA12-010A.html", - "https://security-tracker.debian.org/tracker/CVE-2011-3389", - "http://lists.opensuse.org/opensuse-security-announce/2012-05/msg00009.html", - "http://rhn.redhat.com/errata/RHSA-2013-1455.html", - "https://docs.microsoft.com/en-us/security-updates/securitybulletins/2012/ms12-006", - "http://secunia.com/advisories/55350", - "http://googlechromereleases.blogspot.com/2011/10/chrome-stable-release.html", - "http://lists.opensuse.org/opensuse-security-announce/2020-01/msg00040.html", - "http://www.opera.com/docs/changelogs/windows/1151/", - "http://support.apple.com/kb/HT5281", - "http://support.apple.com/kb/HT6150", - "http://www.debian.org/security/2012/dsa-2398", - "http://www.opera.com/support/kb/view/1004/", - "http://www.educatedguesswork.org/2011/09/security_impact_of_the_rizzodu.html", - "http://marc.info/?l=bugtraq\u0026m=132750579901589\u0026w=2", - "http://isc.sans.edu/diary/SSL+TLS+part+3+/11635", - "http://lists.apple.com/archives/security-announce/2012/Jul/msg00001.html", - "https://h20564.www2.hp.com/portal/site/hpsc/public/kb/docDisplay?docId=emr_na-c03839862", - "http://www.ibm.com/developerworks/java/jdk/alerts/", - "https://bugzilla.novell.com/show_bug.cgi?id=719047", - "http://lists.opensuse.org/opensuse-security-announce/2012-01/msg00051.html", - "http://blogs.technet.com/b/srd/archive/2011/09/26/is-ssl-broken-more-about-security-advisory-2588513.aspx", - "http://curl.haxx.se/docs/adv_20120124B.html", - "http://secunia.com/advisories/48692", - "http://eprint.iacr.org/2006/136", - "http://secunia.com/advisories/55351", - "http://marc.info/?l=bugtraq\u0026m=134254866602253\u0026w=2", - "https://oval.cisecurity.org/repository/search/definition/oval%3Aorg.mitre.oval%3Adef%3A14752", - "http://www.oracle.com/technetwork/topics/security/javacpuoct2011-443431.html", - "http://www.securitytracker.com/id?1025997", - "http://lists.apple.com/archives/security-announce/2013/Oct/msg00004.html", - "http://www.securityfocus.com/bid/49778", - "http://www.insecure.cl/Beast-SSL.rar", - "http://www.mandriva.com/security/advisories?name=MDVSA-2012:058", - "http://www.redhat.com/support/errata/RHSA-2011-1384.html", - "http://rhn.redhat.com/errata/RHSA-2012-0508.html", - "http://secunia.com/advisories/47998", - "http://ekoparty.org/2011/juliano-rizzo.php", - "http://lists.apple.com/archives/security-announce/2012/Sep/msg00004.html", - "http://www.apcmedia.com/salestools/SJHN-7RKGNM/SJHN-7RKGNM_R4_EN.pdf", - "http://www.ubuntu.com/usn/USN-1263-1", - "http://www.oracle.com/technetwork/topics/security/cpujul2015-2367936.html", - "http://security.gentoo.org/glsa/glsa-201406-32.xml", - "http://eprint.iacr.org/2004/111", - "https://ics-cert.us-cert.gov/advisories/ICSMA-18-058-02", - "http://lists.apple.com/archives/security-announce/2012/Feb/msg00000.html", - "http://www.securitytracker.com/id?1026103", - "http://www.opera.com/docs/changelogs/mac/1151/", - "http://secunia.com/advisories/49198", - "http://marc.info/?l=bugtraq\u0026m=132872385320240\u0026w=2", - "http://blog.mozilla.com/security/2011/09/27/attack-against-tls-protected-communications/", - "http://secunia.com/advisories/48915", - "http://lists.apple.com/archives/Security-announce/2011//Oct/msg00001.html", - "http://www.opera.com/docs/changelogs/windows/1160/", - "http://blogs.technet.com/b/msrc/archive/2011/09/26/microsoft-releases-security-advisory-2588513.aspx", - "http://www.imperialviolet.org/2011/09/23/chromeandbeast.html", - "http://lists.opensuse.org/opensuse-security-announce/2012-01/msg00049.html", - "http://www.kb.cert.org/vuls/id/864643", - "http://security.gentoo.org/glsa/glsa-201203-02.xml", - "http://www.oracle.com/technetwork/topics/security/cpujan2015-1972971.html", - "http://osvdb.org/74829", - "http://lists.apple.com/archives/Security-announce/2011//Oct/msg00002.html", - "http://www.securitytracker.com/id/1029190", - "http://marc.info/?l=bugtraq\u0026m=134254957702612\u0026w=2", - "https://hermes.opensuse.org/messages/13154861" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-5981", - "cvss_v3_score": "5.9", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N", - "cwe": [ - "CWE-203" - ], - "cwe_details": { - "CWE-203": { - "name": "Observable Discrepancy", - "description": "The product behaves differently or sends different responses under different circumstances in a way that is observable to an unauthorized actor, which exposes security-relevant information about the state of the product, such as whether a particular operation was successful or not." - } - } - } - ], - "summary": "A vulnerability was found that the response times to malformed ciphertexts in RSA-PSK ClientKeyExchange differ from response times of ciphertexts with correct PKCS#1 v1.5 padding.", - "severity": "Medium", - "components": { - "deb://debian:bookworm:libgnutls30:3.7.9-2": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", - "full_path": "libgnutls30:3.7.9-2" - } - ] - ] - } - }, - "issue_id": "XRAY-537103", - "references": [ - "https://gnutls.org/security-new.html#GNUTLS-SA-2023-10-23", - "https://access.redhat.com/errata/RHSA-2024:0451", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNXKVR5YNUEBNHAHM5GSYKBZX4W2HMN2/", - "http://www.openwall.com/lists/oss-security/2024/01/19/3", - "https://access.redhat.com/errata/RHSA-2024:0533", - "https://bugzilla.redhat.com/show_bug.cgi?id=2248445", - "https://access.redhat.com/errata/RHSA-2024:0319", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/7ZEIOLORQ7N6WRPFXZSYDL2MC4LP7VFV/", - "https://access.redhat.com/errata/RHSA-2024:1383", - "https://access.redhat.com/errata/RHSA-2024:0399", - "https://security-tracker.debian.org/tracker/CVE-2023-5981", - "https://access.redhat.com/security/cve/CVE-2023-5981", - "https://access.redhat.com/errata/RHSA-2024:0155" - ] - }, - { - "cves": [ - { - "cve": "CVE-2024-0567", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-347" - ], - "cwe_details": { - "CWE-347": { - "name": "Improper Verification of Cryptographic Signature", - "description": "The product does not verify, or incorrectly verifies, the cryptographic signature for data." - } - } - } - ], - "summary": "A vulnerability was found in GnuTLS, where a cockpit (which uses gnuTLS) rejects a certificate chain with distributed trust. This issue occurs when validating a certificate chain with cockpit-certificate-ensure. This flaw allows an unauthenticated, remote client or attacker to initiate a denial of service attack.", - "severity": "High", - "components": { - "deb://debian:bookworm:libgnutls30:3.7.9-2": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:libgnutls30:3.7.9-2", - "full_path": "libgnutls30:3.7.9-2" - } - ] - ] - } - }, - "issue_id": "XRAY-588550", - "references": [ - "https://access.redhat.com/errata/RHSA-2024:2094", - "https://access.redhat.com/security/cve/CVE-2024-0567", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/7ZEIOLORQ7N6WRPFXZSYDL2MC4LP7VFV/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNXKVR5YNUEBNHAHM5GSYKBZX4W2HMN2/", - "https://bugzilla.redhat.com/show_bug.cgi?id=2258544", - "http://www.openwall.com/lists/oss-security/2024/01/19/3", - "https://security.netapp.com/advisory/ntap-20240202-0011/", - "https://access.redhat.com/errata/RHSA-2024:1383", - "https://lists.gnupg.org/pipermail/gnutls-help/2024-January/004841.html", - "https://access.redhat.com/errata/RHSA-2024:1082", - "https://security-tracker.debian.org/tracker/CVE-2024-0567", - "https://gitlab.com/gnutls/gnutls/-/issues/1521", - "https://access.redhat.com/errata/RHSA-2024:0533" - ], - "extended_information": { - "short_description": "A design problem in GnuTLS may lead to denial of service when parsing a crafted certificate chain.", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The given CVSS score does not take into account the prerequisites and context required to exploit the vulnerability.", - "is_positive": true - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The vulnerability is only exploitable if a GnuTLS client or server calls any of the following functions with externally-supplied input -\n\n- `gnutls_pcert_import_x509_list`\n\n- `gnutls_certificate_set_x509_key`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_mem`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_file`\n\n- `gnutls_privkey_import_url`\n\n- `gnutls_privkey_import_pkcs11_url`\n\n- `gnutls_read_key_file`\n\n- `gnutls_certificate_set_rawpk_key_file`\n\n- `gnutls_certificate_set_x509_key_file2`\n\n- `gnutls_certificate_set_x509_key_file`\n\n- `gnutls_pcert_list_import_x509_file`\n\n- `gnutls_certificate_set_x509_key_mem2`\n\n- `gnutls_certificate_set_x509_key_mem`\n\n- `gnutls_x509_crt_list_import`\n\n- `gnutls_pcert_list_import_x509_raw`\n\n- `gnutls_session_channel_binding`\n\n- `gnutls_x509_crt_list_import2`\n\n- `gnutls_x509_trust_list_add_trust_mem`\n\n- `gnutls_x509_trust_list_add_system_trust`\n\n- `gnutls_certificate_set_x509_system_trust`\n\n- `gnutls_certificate_set_x509_crl_mem`\n\n- `gnutls_certificate_set_x509_trust_mem`\n\n- `gnutls_x509_trust_list_add_trust_file`\n\n- `gnutls_certificate_set_x509_crl_file`\n\n- `gnutls_certificate_set_x509_trust_file`\n\n- `gnutls_x509_trust_list_add_trust_dir`\n\n- `gnutls_certificate_set_x509_trust_dir`\n\n- `gnutls_x509_trust_list_remove_trust_mem`\n\n- `gnutls_x509_trust_list_remove_trust_file`\n\n- `gnutls_x509_trust_list_verify_crt2`\n\n- `gnutls_x509_cert_verify_peers`\n\n- `gnutls_certificate_verify_peers`\n\n- `gnutls_certificate_verify_peers2`\n\n- `gnutls_certificate_verify_peers3`\n\n- `gnutls_pkcs7_verify`\n\n- `gnutls_ocsp_resp_verify`\n\n- `gnutls_x509_trust_list_verify_crt`", - "is_positive": true - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2021-4214", - "cvss_v3_score": "5.5", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H", - "cwe": [ - "CWE-120" - ], - "cwe_details": { - "CWE-120": { - "name": "Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')", - "description": "The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow." - } - } - } - ], - "summary": "A heap overflow flaw was found in libpngs' pngimage.c program. This flaw allows an attacker with local network access to pass a specially crafted PNG file to the pngimage utility, causing an application to crash, leading to a denial of service.", - "severity": "Low", - "components": { - "deb://debian:bookworm:libpng16-16:1.6.39-2": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed/sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar", - "full_path": "sha256__6cd9f01fb9e511a9e611c6592d62412c0fead4b2b09dc3de7fbf6b50a8df0eed.tar" - }, - { - "component_id": "deb://debian:bookworm:libpng16-16:1.6.39-2", - "full_path": "libpng16-16:1.6.39-2" - } - ] - ] - } - }, - "issue_id": "XRAY-196432", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2021-4214", - "https://security.netapp.com/advisory/ntap-20221020-0001/", - "https://github.com/glennrp/libpng/issues/302", - "https://access.redhat.com/security/cve/CVE-2021-4214", - "https://bugzilla.redhat.com/show_bug.cgi?id=2043393" - ] - }, - { - "cves": [ - { - "cve": "CVE-2011-4116", - "cvss_v2_score": "5.0", - "cvss_v2_vector": "CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:P/A:N", - "cvss_v3_score": "7.5", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", - "cwe": [ - "CWE-59" - ], - "cwe_details": { - "CWE-59": { - "name": "Improper Link Resolution Before File Access ('Link Following')", - "description": "The product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource." - } - } - } - ], - "summary": "_is_safe in the File::Temp module for Perl does not properly handle symlinks.", - "severity": "Low", - "components": { - "deb://debian:bookworm:perl-base:5.36.0-7": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:perl-base:5.36.0-7", - "full_path": "perl-base:5.36.0-7" - } - ] - ] - } - }, - "issue_id": "XRAY-36310", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2011-4116", - "https://seclists.org/oss-sec/2011/q4/238", - "https://github.com/Perl-Toolchain-Gang/File-Temp/issues/14", - "http://www.openwall.com/lists/oss-security/2011/11/04/2", - "https://rt.cpan.org/Public/Bug/Display.html?id=69106", - "http://www.openwall.com/lists/oss-security/2011/11/04/4" - ] - }, - { - "cves": [ - { - "cve": "CVE-2023-31486", - "cvss_v3_score": "8.1", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-295" - ], - "cwe_details": { - "CWE-295": { - "name": "Improper Certificate Validation", - "description": "The product does not validate, or incorrectly validates, a certificate." - } - } - } - ], - "summary": "HTTP::Tiny before 0.083, a Perl core module since 5.13.9 and available standalone on CPAN, has an insecure default TLS configuration where users must opt in to verify certificates.", - "severity": "Low", - "components": { - "deb://debian:bookworm:perl-base:5.36.0-7": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:perl-base:5.36.0-7", - "full_path": "perl-base:5.36.0-7" - } - ] - ] - } - }, - "issue_id": "XRAY-515822", - "references": [ - "https://github.com/chansen/p5-http-tiny/pull/153", - "https://security-tracker.debian.org/tracker/CVE-2023-31486", - "http://www.openwall.com/lists/oss-security/2023/05/07/2", - "http://www.openwall.com/lists/oss-security/2023/04/29/1", - "http://www.openwall.com/lists/oss-security/2023/05/03/5", - "http://www.openwall.com/lists/oss-security/2023/05/03/3", - "https://www.reddit.com/r/perl/comments/111tadi/psa_httptiny_disabled_ssl_verification_by_default/", - "https://www.openwall.com/lists/oss-security/2023/05/03/4", - "https://hackeriet.github.io/cpan-http-tiny-overview/", - "https://blog.hackeriet.no/perl-http-tiny-insecure-tls-default-affects-cpan-modules/", - "https://www.openwall.com/lists/oss-security/2023/04/18/14" - ], - "extended_information": { - "short_description": "Missing TLS check in HTTP::Tiny allows network attackers to perform man-in-the-middle attacks when performing SSL requests.", - "full_description": "[HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) is an HTTP client written in Perl and a standalone CPAN module. By default, HTTP::Tiny does not verify TLS certificates. To enable verification, the `verify_SSL=\u003e1` flag must be specified when initializing the `HTTP::Tiny` object.\n\nThis could allow potential local-network attacker to perform a man-in-the-middle (ssl strip) attack.\nThis issue affects all packages that incorrectly use the `HTTP::Tiny` package.\n\nVulnerable code snippet -\n```\nuse HTTP::Tiny;\n\nmy $http = HTTP::Tiny-\u003enew();\nmy $response = $http-\u003eget('https://example.com');\n```", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue is trivial to exploit and does not require a published writeup or PoC", - "description": "Exploitation only requires an attacker to perform a man-in-the-middle attack (which is extensively documented)." - }, - { - "name": "The issue has a detailed technical explanation published, that can aid in exploit development", - "description": "A technical write-up exists." - }, - { - "name": "The issue can be exploited by attackers over the network", - "description": "The vulnerability is exploitable by local network attackers" - }, - { - "name": "The impact of exploiting the issue depends on the context of surrounding software. A severe impact such as RCE is not guaranteed.", - "description": "The impact depends on the action performed by the vulnerable code.\nThis could be anything from information disclosure (through the web requests) to remote code execution (in the event the request response is used to install a package or influence the application's flow).", - "is_positive": true - } - ], - "remediation": "##### Development mitigations\n\nEnable the `verify_SSL` flag when initializing HTTP::Tiny -\n\n```perl\n$http = HTTP::Tiny-\u003enew(verify_SSL=\u003e1);\n```" - } - }, - { - "cves": [ - { - "cve": "CVE-2023-47038", - "cvss_v3_score": "7.8", - "cvss_v3_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-787" - ], - "cwe_details": { - "CWE-787": { - "name": "Out-of-bounds Write", - "description": "The product writes data past the end, or before the beginning, of the intended buffer.", - "categories": [ - { - "category": "2023 CWE Top 25", - "rank": "1" - } - ] - } - } - } - ], - "summary": "A vulnerability was found in perl 5.30.0 through 5.38.0. This issue occurs when a crafted regular expression is compiled by perl, which can allow an attacker controlled byte buffer overflow in a heap allocated buffer.", - "severity": "High", - "components": { - "deb://debian:bookworm:perl-base:5.36.0-7": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:perl-base:5.36.0-7", - "full_path": "perl-base:5.36.0-7" - } - ] - ] - } - }, - "issue_id": "XRAY-539839", - "references": [ - "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1056746", - "https://access.redhat.com/errata/RHSA-2024:3128", - "https://access.redhat.com/security/cve/CVE-2023-47038", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GNEEWAACXQCEEAKSG7XX2D5YDRWLCIZJ/", - "https://security-tracker.debian.org/tracker/CVE-2023-47038", - "https://bugzilla.redhat.com/show_bug.cgi?id=2249523", - "https://perldoc.perl.org/perl5382delta#CVE-2023-47038-Write-past-buffer-end-via-illegal-user-defined-Unicode-property", - "https://access.redhat.com/errata/RHSA-2024:2228" - ], - "extended_information": { - "short_description": "(non-issue) A heap buffer overflow in Perl leads to no impact when parsing a crafted regular expression.", - "jfrog_research_severity": "Low", - "jfrog_research_severity_reasons": [ - { - "name": "The issue has an exploit published", - "description": "A test case is given, and is included in the Debian advisory:\n`perl -e 'qr/\\p{utf8::_perl_surrogate}/'`" - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "If the attacker can execute arbitrary Perl code, exploiting the vulnerability would offer no additional security impact.", - "is_positive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The CVSS impact does not reflect the prerequisites required to exploit the vulnerability.", - "is_positive": true - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "The attacker must be able to run Perl code which the victim executes.", - "is_positive": true - } - ] - } - }, - { - "cves": [ - { - "cve": "CVE-2023-31484", - "cvss_v3_score": "8.1", - "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H", - "cwe": [ - "CWE-295" - ], - "cwe_details": { - "CWE-295": { - "name": "Improper Certificate Validation", - "description": "The product does not validate, or incorrectly validates, a certificate." - } - } - } - ], - "summary": "CPAN.pm before 2.35 does not verify TLS certificates when downloading distributions over HTTPS.", - "severity": "High", - "components": { - "deb://debian:bookworm:perl-base:5.36.0-7": { - "impact_paths": [ - [ - { - "component_id": "docker://docker.io/library/nginx:latest" - }, - { - "component_id": "generic://sha256:32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027/sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar", - "full_path": "sha256__32f2ee38f285d7a349380070ea0dbfa284c9181e5e8b1a736f7a9eca726b1027.tar" - }, - { - "component_id": "deb://debian:bookworm:perl-base:5.36.0-7", - "full_path": "perl-base:5.36.0-7" - } - ] - ] - } - }, - "issue_id": "XRAY-515823", - "references": [ - "http://www.openwall.com/lists/oss-security/2023/04/29/1", - "https://security.netapp.com/advisory/ntap-20240621-0007/", - "http://www.openwall.com/lists/oss-security/2023/05/03/5", - "http://www.openwall.com/lists/oss-security/2023/05/03/3", - "https://blog.hackeriet.no/perl-http-tiny-insecure-tls-default-affects-cpan-modules/", - "http://www.openwall.com/lists/oss-security/2023/05/07/2", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/BM6UW55CNFUTNGD5ZRKGUKKKFDJGMFHL/", - "https://metacpan.org/dist/CPAN/changes", - "https://security-tracker.debian.org/tracker/CVE-2023-31484", - "https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LEGCEOKFJVBJ2QQ6S2H4NAEWTUERC7SB/", - "https://github.com/andk/cpanpm/pull/175", - "https://www.openwall.com/lists/oss-security/2023/04/18/14" - ], - "extended_information": { - "short_description": "Missing TLS check in CPAN.pm allows man-in-the-middle attacks when downloading packages and may lead to code execution.", - "full_description": "[CPAN.pm](https://metacpan.org/pod/CPAN) is a Perl module and command-line tool that provides an automated and standardized way to download, install, and manage Perl modules and their dependencies from the Comprehensive Perl Archive Network (CPAN).\n[HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) is an HTTP client in Perl and a standalone CPAN module. By default, it does not verify TLS certificates. To enable it, the `verify_SSL=\u003e1` flag should be specified when initializing the `HTTP::Tiny` object. The problem identified in `HTTP::Tiny` has been assigned the CVE identifier `CVE-2023-31486` and serves as the underlying cause for the problem in `CPAN.pm`.\n\n`CPAN.pm` downloads and executes code through the `install` command followed by the package name.\nAlthough `CPAN.pm` downloads from `https://cpan.org`, it does not enable TLS certificate verification while using `HTTP::Tiny`, which could potentially allow an attacker to perform a man-in-the-middle attack by injecting malicious data that could be executed by CPAN.pm.\n\nExample of a vulnerable code:\n```\nuse CPAN;\ninstall DateTime\n```\n\nExample of a vulnerable command-line:\n```\ncpan install DateTime\n```", - "jfrog_research_severity": "High", - "jfrog_research_severity_reasons": [ - { - "name": "The issue is trivial to exploit and does not require a published writeup or PoC", - "description": "Exploitation only requires an attacker to perform a man-in-the-middle attack (which is extensively documented) and provide the victim with a malicious package instead of the legitimate one." - }, - { - "name": "The issue has a detailed technical explanation published, that can aid in exploit development", - "description": "A technical write-up exists." - }, - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The attacker should be in the network to perform a man-in-the-middle attack, and then provide a malicious package when the victim installs a new CPAN.pm package.", - "is_positive": true - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "This issue may lead to code execution." - }, - { - "name": "The issue can be exploited by attackers over the network" - } - ] - } - } - ], - "component_id": "docker://docker.io/library/nginx:latest", - "package_type": "oci", - "status": "completed" - } - ] - }, - "jas_scans": { - "contextual_analysis": [ - { - "tool": { - "driver": { - "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", - "name": "JFrog Applicability Scanner", - "rules": [ - { - "id": "applic_CVE-2011-3374", - "name": "CVE-2011-3374", - "shortDescription": { - "text": "Scanner for CVE-2011-3374" - }, - "fullDescription": { - "text": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", - "markdown": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2013-0337", - "name": "CVE-2013-0337", - "shortDescription": { - "text": "Scanner for CVE-2013-0337" - }, - "fullDescription": { - "text": "The scanner checks whether any of the Nginx log files (`error.log` and `access.log`) is a symbolic link. If both files are symbolic links that point to `\\dev\\*` path, the vulnerability is not relevant, thus not applicable. If one of the log files is not a symbolic link, the vulnerability is applicable.", - "markdown": "The scanner checks whether any of the Nginx log files (`error.log` and `access.log`) is a symbolic link. If both files are symbolic links that point to `\\dev\\*` path, the vulnerability is not relevant, thus not applicable. If one of the log files is not a symbolic link, the vulnerability is applicable." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2018-5709", - "name": "CVE-2018-5709", - "shortDescription": { - "text": "Scanner for CVE-2018-5709" - }, - "fullDescription": { - "text": "This CVE has no security impact, hence it is never applicable.\nOriginally, the vulnerability was mistakenly reported as an integer overflow, but it is actually an integer truncation.\nThe issue does not affect any other data allocated close to the 16-bit integer in question. Furthermore, a negative value of the 16-bit integer does not impact the flow of the program in any meaningful way.", - "markdown": "This CVE has no security impact, hence it is never applicable.\nOriginally, the vulnerability was mistakenly reported as an integer overflow, but it is actually an integer truncation.\nThe issue does not affect any other data allocated close to the 16-bit integer in question. Furthermore, a negative value of the 16-bit integer does not impact the flow of the program in any meaningful way." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2024-5171", - "name": "CVE-2024-5171", - "shortDescription": { - "text": "Scanner for CVE-2024-5171" - }, - "fullDescription": { - "text": "The scanner checks whether any of the vulnerable functions are called:\n\n* `aom_img_alloc()`\n\n* `aom_img_wrap()`\n\n* `aom_img_alloc_with_border()`", - "markdown": "The scanner checks whether any of the vulnerable functions are called:\n\n* `aom_img_alloc()`\n\n* `aom_img_wrap()`\n\n* `aom_img_alloc_with_border()`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-39616", - "name": "CVE-2023-39616", - "shortDescription": { - "text": "Scanner for CVE-2023-39616" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable function `aom_codec_encode` is called.\n\nIn order for the vulnerability to be fully applicable, the vulnerable code must also call the `aom_codec_enc_init` function with the 3rd argument struct (`config`) being set with `dropframe_thresh` == 1. This additional condition is currently not checked by the scanner.\n\nNote that the vulnerability is also exploitable through the CLI tool `aomenc` under rare conditions. However - exploitation of the CLI tool will cause it to simply crash, which has no security impact (crashing of a forked client process).", - "markdown": "The scanner checks whether the vulnerable function `aom_codec_encode` is called.\n\nIn order for the vulnerability to be fully applicable, the vulnerable code must also call the `aom_codec_enc_init` function with the 3rd argument struct (`config`) being set with `dropframe_thresh` == 1. This additional condition is currently not checked by the scanner.\n\nNote that the vulnerability is also exploitable through the CLI tool `aomenc` under rare conditions. However - exploitation of the CLI tool will cause it to simply crash, which has no security impact (crashing of a forked client process)." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2022-0563", - "name": "CVE-2022-0563", - "shortDescription": { - "text": "Scanner for CVE-2022-0563" - }, - "fullDescription": { - "text": "The scanner checks whether the `chfs` and `chfn` CLI utilities are compiled with the vulnerable `readline` library.", - "markdown": "The scanner checks whether the `chfs` and `chfn` CLI utilities are compiled with the vulnerable `readline` library." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-27103", - "name": "CVE-2023-27103", - "shortDescription": { - "text": "Scanner for CVE-2023-27103" - }, - "fullDescription": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`", - "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-49465", - "name": "CVE-2023-49465", - "shortDescription": { - "text": "Scanner for CVE-2023-49465" - }, - "fullDescription": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`", - "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-49467", - "name": "CVE-2023-49467", - "shortDescription": { - "text": "Scanner for CVE-2023-49467" - }, - "fullDescription": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`", - "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-49468", - "name": "CVE-2023-49468", - "shortDescription": { - "text": "Scanner for CVE-2023-49468" - }, - "fullDescription": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`", - "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-52425", - "name": "CVE-2023-52425", - "shortDescription": { - "text": "Scanner for CVE-2023-52425" - }, - "fullDescription": { - "text": "The scanner checks whether any of the next functions are called:\n\n* `XML_Parse()`\n* `XML_ParseBuffer()`\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: The vulnerable functions are used to parse an attacker-controlled file by chunks.", - "markdown": "The scanner checks whether any of the next functions are called:\n\n* `XML_Parse()`\n* `XML_ParseBuffer()`\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: The vulnerable functions are used to parse an attacker-controlled file by chunks." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2024-45490", - "name": "CVE-2024-45490", - "shortDescription": { - "text": "Scanner for CVE-2024-45490" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `XML_Parse()`\n- `XML_ParseBuffer()`\n\nAn additional condition, which the scanner currently does not check, is that the `len` parameter which is passed to those functions is user-controlled.", - "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `XML_Parse()`\n- `XML_ParseBuffer()`\n\nAn additional condition, which the scanner currently does not check, is that the `len` parameter which is passed to those functions is user-controlled." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-26965", - "name": "CVE-2023-26965", - "shortDescription": { - "text": "Scanner for CVE-2023-26965" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable `tiffcrop` binary is present in the image.\n\nNote that the scanner does not check whether `tiffcrop` is invoked with arbitrary image files.", - "markdown": "The scanner checks whether the vulnerable `tiffcrop` binary is present in the image.\n\nNote that the scanner does not check whether `tiffcrop` is invoked with arbitrary image files." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-2953", - "name": "CVE-2023-2953", - "shortDescription": { - "text": "Scanner for CVE-2023-2953" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following vulnerable functions are used:\n\n- `ldif_open_url`\n- `ldif_fetch_url`\n- `ldif_parse_line2`\n- `ldif_parse_line`\n- `ldap_parse_ldif_record_x`\n- `ldap_parse_ldif_record`\n- `ldif_read_record`\n- `slapi_str2entry`", - "markdown": "The scanner checks whether any of the following vulnerable functions are used:\n\n- `ldif_open_url`\n- `ldif_fetch_url`\n- `ldif_parse_line2`\n- `ldif_parse_line`\n- `ldap_parse_ldif_record_x`\n- `ldap_parse_ldif_record`\n- `ldif_read_record`\n- `slapi_str2entry`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-40745", - "name": "CVE-2023-40745", - "shortDescription": { - "text": "Scanner for CVE-2023-40745" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-41175", - "name": "CVE-2023-41175", - "shortDescription": { - "text": "Scanner for CVE-2023-41175" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-43887", - "name": "CVE-2023-43887", - "shortDescription": { - "text": "Scanner for CVE-2023-43887" - }, - "fullDescription": { - "text": "The scanner checks for the presence of a binary related to `libde265` on the scanned artifact, specifically, any file ending with `dec265`.", - "markdown": "The scanner checks for the presence of a binary related to `libde265` on the scanned artifact, specifically, any file ending with `dec265`." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-44487", - "name": "CVE-2023-44487", - "shortDescription": { - "text": "Scanner for CVE-2023-44487" - }, - "fullDescription": { - "text": "The scanner checks for each vendor listed here:\n\n* Tomcat: configuration enables HTTP/2 either through the XML file or Java's `addUpgradeProtocol()` method.\n* Jetty: HTTP/2 enabled through `HTTP2CServerConnectionFactory`/`HTTP2ServerConnectionFactory` class initialization. Note: it also checks whether `jenkins` enables http/2 through its configuration.\n* Nginx: check whether one of the HTTP configurations is enabling http/2.\nNote: the following parameters should be configured properly to make the vulnerability not applicable:\n`keepalive_requests` should be kept at the default setting of 1000 requests\n`http2_max_concurrent_streams` should be kept at the default setting of 128 streams\n`limit_conn and limit_req` should be set `with a reasonable setting balancing application performance and security`. \n* Netty: check whether the `http2` codec classes are used in a java class\n* NodeJS: check whether the `http2.createSecureServer()` is used\n* NGHttp2: check whether a web server is instantiated through one of the symbols `nghttp2_session_server_new` or `listen_and_serve`.\n* Go: check whether a server is instantiated through the `net/http` or `net/http2` packages", - "markdown": "The scanner checks for each vendor listed here:\n\n* Tomcat: configuration enables HTTP/2 either through the XML file or Java's `addUpgradeProtocol()` method.\n* Jetty: HTTP/2 enabled through `HTTP2CServerConnectionFactory`/`HTTP2ServerConnectionFactory` class initialization. Note: it also checks whether `jenkins` enables http/2 through its configuration.\n* Nginx: check whether one of the HTTP configurations is enabling http/2.\nNote: the following parameters should be configured properly to make the vulnerability not applicable:\n`keepalive_requests` should be kept at the default setting of 1000 requests\n`http2_max_concurrent_streams` should be kept at the default setting of 128 streams\n`limit_conn and limit_req` should be set `with a reasonable setting balancing application performance and security`. \n* Netty: check whether the `http2` codec classes are used in a java class\n* NodeJS: check whether the `http2.createSecureServer()` is used\n* NGHttp2: check whether a web server is instantiated through one of the symbols `nghttp2_session_server_new` or `listen_and_serve`.\n* Go: check whether a server is instantiated through the `net/http` or `net/http2` packages" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-45853", - "name": "CVE-2023-45853", - "shortDescription": { - "text": "Scanner for CVE-2023-45853" - }, - "fullDescription": { - "text": "The scanner checks if any of the following functions are called:\n\n- `zipOpenNewFileInZip`\n- `zipOpenNewFileInZip_64`\n- `zipOpenNewFileInZip2`\n- `zipOpenNewFileInZip2_64`\n- `zipOpenNewFileInZip3`\n- `zipOpenNewFileInZip3_64`\n- `zipOpenNewFileInZip4`\n- `zipOpenNewFileInZip4_64`", - "markdown": "The scanner checks if any of the following functions are called:\n\n- `zipOpenNewFileInZip`\n- `zipOpenNewFileInZip_64`\n- `zipOpenNewFileInZip2`\n- `zipOpenNewFileInZip2_64`\n- `zipOpenNewFileInZip3`\n- `zipOpenNewFileInZip3_64`\n- `zipOpenNewFileInZip4`\n- `zipOpenNewFileInZip4_64`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-47038", - "name": "CVE-2023-47038", - "shortDescription": { - "text": "Scanner for CVE-2023-47038" - }, - "fullDescription": { - "text": "This CVE has no security impact (hence it is never applicable) as one of its prerequisites is arbitrary execution of Perl code, making any security impact of exploiting the vulnerability negligible since arbitrary code execution has already occurred.", - "markdown": "This CVE has no security impact (hence it is never applicable) as one of its prerequisites is arbitrary execution of Perl code, making any security impact of exploiting the vulnerability negligible since arbitrary code execution has already occurred." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-49460", - "name": "CVE-2023-49460", - "shortDescription": { - "text": "Scanner for CVE-2023-49460" - }, - "fullDescription": { - "text": "The scanner checks if the `libheif` binary was compiled with the vulnerable setting `-DWITH_UNCOMPRESSED_CODEC=ON` and if the vulnerable function `UncompressedImageCodec::decode_uncompressed_image` is called.", - "markdown": "The scanner checks if the `libheif` binary was compiled with the vulnerable setting `-DWITH_UNCOMPRESSED_CODEC=ON` and if the vulnerable function `UncompressedImageCodec::decode_uncompressed_image` is called." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-49463", - "name": "CVE-2023-49463", - "shortDescription": { - "text": "Scanner for CVE-2023-49463" - }, - "fullDescription": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `read_exif_orientation_tag`\n\n* `modify_exif_orientation_tag_if_it_exists`", - "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n* `read_exif_orientation_tag`\n\n* `modify_exif_orientation_tag_if_it_exists`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-49462", - "name": "CVE-2023-49462", - "shortDescription": { - "text": "Scanner for CVE-2023-49462" - }, - "fullDescription": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `read_exif_orientation_tag`\n\n* `modify_exif_orientation_tag_if_it_exists`", - "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n* `read_exif_orientation_tag`\n\n* `modify_exif_orientation_tag_if_it_exists`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-50387", - "name": "CVE-2023-50387", - "shortDescription": { - "text": "Scanner for CVE-2023-50387" - }, - "fullDescription": { - "text": "The scanner checks whether DNSSEC validation is on. Currently, the supported packages are `bind`, `dnsmasq`, `systemd`, `unbound`.\nFor bind, the scanner checks whether `dnssec-validation` configuration option is set to `auto` or `yes` in the bind configuration file.\n\nFor dnsmasq, the scanner checks whether the `dnssec` configuration appears in the dnsmasq configuration file.\n\nFor systemd, the scanner checks whether the `DNSSEC` configuration is set to `true` or `allow-downgrade` in the systemd-resolved configuration file.\n\nFor unbound, the scanner checks whether a `trust-anchor-file` or `auto-trust-anchor-file` file is set in the `server` configuration in the Unbound configuration file.\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: the attacker must be able to query the DNSSEC resolver to validate their malicious domain.", - "markdown": "The scanner checks whether DNSSEC validation is on. Currently, the supported packages are `bind`, `dnsmasq`, `systemd`, `unbound`.\nFor bind, the scanner checks whether `dnssec-validation` configuration option is set to `auto` or `yes` in the bind configuration file.\n\nFor dnsmasq, the scanner checks whether the `dnssec` configuration appears in the dnsmasq configuration file.\n\nFor systemd, the scanner checks whether the `DNSSEC` configuration is set to `true` or `allow-downgrade` in the systemd-resolved configuration file.\n\nFor unbound, the scanner checks whether a `trust-anchor-file` or `auto-trust-anchor-file` file is set in the `server` configuration in the Unbound configuration file.\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: the attacker must be able to query the DNSSEC resolver to validate their malicious domain." - }, - "properties": { - "applicability": "undetermined", - "conclusion": "private" - } - }, - { - "id": "applic_CVE-2023-50868", - "name": "CVE-2023-50868", - "shortDescription": { - "text": "Scanner for CVE-2023-50868" - }, - "fullDescription": { - "text": "The scanner checks whether DNSSEC validation is on. Currently, the supported packages are `bind`, `dnsmasq`, `systemd`, `unbound`.\nFor bind, the scanner checks whether `dnssec-validation` configuration option is set to `auto` or `yes` in the bind configuration file.\n\nFor dnsmasq, the scanner checks whether the `dnssec` configuration appears in the dnsmasq configuration file.\n\nFor systemd, the scanner checks whether the `DNSSEC` configuration is set to `true` or `allow-downgrade` in the systemd-resolved configuration file.\n\nFor unbound, the scanner checks whether a `trust-anchor-file` or `auto-trust-anchor-file` file is set in the `server` configuration in the Unbound configuration file.\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: the attacker must be able to query the DNSSEC resolver to validate their malicious domain.", - "markdown": "The scanner checks whether DNSSEC validation is on. Currently, the supported packages are `bind`, `dnsmasq`, `systemd`, `unbound`.\nFor bind, the scanner checks whether `dnssec-validation` configuration option is set to `auto` or `yes` in the bind configuration file.\n\nFor dnsmasq, the scanner checks whether the `dnssec` configuration appears in the dnsmasq configuration file.\n\nFor systemd, the scanner checks whether the `DNSSEC` configuration is set to `true` or `allow-downgrade` in the systemd-resolved configuration file.\n\nFor unbound, the scanner checks whether a `trust-anchor-file` or `auto-trust-anchor-file` file is set in the `server` configuration in the Unbound configuration file.\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: the attacker must be able to query the DNSSEC resolver to validate their malicious domain." - }, - "properties": { - "applicability": "undetermined", - "conclusion": "private" - } - }, - { - "id": "applic_CVE-2023-52355", - "name": "CVE-2023-52355", - "shortDescription": { - "text": "Scanner for CVE-2023-52355" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following functions are called:\n\n- `TIFFRasterScanlineSize64()`\n- `TIFFRasterScanlineSize()`", - "markdown": "The scanner checks whether any of the following functions are called:\n\n- `TIFFRasterScanlineSize64()`\n- `TIFFRasterScanlineSize()`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-52356", - "name": "CVE-2023-52356", - "shortDescription": { - "text": "Scanner for CVE-2023-52356" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following functions are called:\n\n- `TIFFReadRGBATileExt()` \n- `TIFFReadRGBATile()`", - "markdown": "The scanner checks whether any of the following functions are called:\n\n- `TIFFReadRGBATileExt()` \n- `TIFFReadRGBATile()`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-5363", - "name": "CVE-2023-5363", - "shortDescription": { - "text": "Scanner for CVE-2023-5363" - }, - "fullDescription": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n- `EVP_EncryptInit_ex2`\n- `EVP_DecryptInit_ex2`\n- `EVP_CipherInit_ex2`", - "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n- `EVP_EncryptInit_ex2`\n- `EVP_DecryptInit_ex2`\n- `EVP_CipherInit_ex2`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-6246", - "name": "CVE-2023-6246", - "shortDescription": { - "text": "Scanner for CVE-2023-6246" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable functions `syslog` or `vsyslog` are called from a file with the `setuid` or `setgid` bit.\n\nTo exploit this vulnerability, the attacker needs to control either argv[0], which typically holds the name of the program being executed or the `ident` argument of syslog's `openlog()` function. The scanner currently does not verify this prerequisite but for local exploitation, it is a common scenraio, such as in `su` binary.", - "markdown": "The scanner checks whether the vulnerable functions `syslog` or `vsyslog` are called from a file with the `setuid` or `setgid` bit.\n\nTo exploit this vulnerability, the attacker needs to control either argv[0], which typically holds the name of the program being executed or the `ident` argument of syslog's `openlog()` function. The scanner currently does not verify this prerequisite but for local exploitation, it is a common scenraio, such as in `su` binary." - }, - "properties": { - "applicability": "applicable", - "conclusion": "negative", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-6879", - "name": "CVE-2023-6879", - "shortDescription": { - "text": "Scanner for CVE-2023-6879" - }, - "fullDescription": { - "text": "The scanner checks whether an encoding process is performed with the following requirements:\n\n* Using AV1 codec (`aom_codec_av1_cx()`).\n* Encoding (`aom_codec_encode()`)\n* Cleaning the memory at the end of the encoding process (`aom_codec_destroy()`).\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: `aom` is configured to use more than 1 thread. For example:\n```\naom_codec_enc_cfg_t cfg;\naom_codec_enc_config_default(iface, \u0026cfg, AOM_USAGE_GOOD_QUALITY));\ncfg.g_threads = 4;\n```", - "markdown": "The scanner checks whether an encoding process is performed with the following requirements:\n\n* Using AV1 codec (`aom_codec_av1_cx()`).\n* Encoding (`aom_codec_encode()`)\n* Cleaning the memory at the end of the encoding process (`aom_codec_destroy()`).\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: `aom` is configured to use more than 1 thread. For example:\n```\naom_codec_enc_cfg_t cfg;\naom_codec_enc_config_default(iface, \u0026cfg, AOM_USAGE_GOOD_QUALITY));\ncfg.g_threads = 4;\n```" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2024-0553", - "name": "CVE-2024-0553", - "shortDescription": { - "text": "Scanner for CVE-2024-0553" - }, - "fullDescription": { - "text": "The scanner checks if RSA decryption occurs by finding calls to any of the following functions:\n\n- `gnutls_privkey_decrypt_data`\n\n- `gnutls_privkey_decrypt_data2`\n\nAn additional condition (that the scanner does not currently check) is required for the CVE to be applicable: the RSA padding algorithm needs to be `PKCS#1`. `key-\u003epk_algorithm` needs to be equal to `GNUTLS_PK_RSA`.", - "markdown": "The scanner checks if RSA decryption occurs by finding calls to any of the following functions:\n\n- `gnutls_privkey_decrypt_data`\n\n- `gnutls_privkey_decrypt_data2`\n\nAn additional condition (that the scanner does not currently check) is required for the CVE to be applicable: the RSA padding algorithm needs to be `PKCS#1`. `key-\u003epk_algorithm` needs to be equal to `GNUTLS_PK_RSA`." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2024-0567", - "name": "CVE-2024-0567", - "shortDescription": { - "text": "Scanner for CVE-2024-0567" - }, - "fullDescription": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n- `gnutls_pcert_import_x509_list`\n\n- `gnutls_certificate_set_x509_key`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_mem`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_file`\n\n- `gnutls_privkey_import_url`\n\n- `gnutls_privkey_import_pkcs11_url`\n\n- `gnutls_read_key_file`\n\n- `gnutls_certificate_set_rawpk_key_file`\n\n- `gnutls_certificate_set_x509_key_file2`\n\n- `gnutls_certificate_set_x509_key_file`\n\n- `gnutls_pcert_list_import_x509_file`\n\n- `gnutls_certificate_set_x509_key_mem2`\n\n- `gnutls_certificate_set_x509_key_mem`\n\n- `gnutls_x509_crt_list_import`\n\n- `gnutls_pcert_list_import_x509_raw`\n\n- `gnutls_session_channel_binding`\n\n- `gnutls_x509_crt_list_import2`\n\n- `gnutls_x509_trust_list_add_trust_mem`\n\n- `gnutls_x509_trust_list_add_system_trust`\n\n- `gnutls_certificate_set_x509_system_trust`\n\n- `gnutls_certificate_set_x509_crl_mem`\n\n- `gnutls_certificate_set_x509_trust_mem`\n\n- `gnutls_x509_trust_list_add_trust_file`\n\n- `gnutls_certificate_set_x509_crl_file`\n\n- `gnutls_certificate_set_x509_trust_file`\n\n- `gnutls_x509_trust_list_add_trust_dir`\n\n- `gnutls_certificate_set_x509_trust_dir`\n\n- `gnutls_x509_trust_list_remove_trust_mem`\n\n- `gnutls_x509_trust_list_remove_trust_file`\n\n- `gnutls_x509_trust_list_verify_crt2`\n\n- `gnutls_x509_cert_verify_peers`\n\n- `gnutls_certificate_verify_peers`\n\n- `gnutls_certificate_verify_peers2`\n\n- `gnutls_certificate_verify_peers3`\n\n- `gnutls_pkcs7_verify`\n\n- `gnutls_ocsp_resp_verify`\n\n- `gnutls_x509_trust_list_verify_crt`", - "markdown": "The scanner checks if any of the following vulnerable functions are called:\n\n- `gnutls_pcert_import_x509_list`\n\n- `gnutls_certificate_set_x509_key`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_mem`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_file`\n\n- `gnutls_privkey_import_url`\n\n- `gnutls_privkey_import_pkcs11_url`\n\n- `gnutls_read_key_file`\n\n- `gnutls_certificate_set_rawpk_key_file`\n\n- `gnutls_certificate_set_x509_key_file2`\n\n- `gnutls_certificate_set_x509_key_file`\n\n- `gnutls_pcert_list_import_x509_file`\n\n- `gnutls_certificate_set_x509_key_mem2`\n\n- `gnutls_certificate_set_x509_key_mem`\n\n- `gnutls_x509_crt_list_import`\n\n- `gnutls_pcert_list_import_x509_raw`\n\n- `gnutls_session_channel_binding`\n\n- `gnutls_x509_crt_list_import2`\n\n- `gnutls_x509_trust_list_add_trust_mem`\n\n- `gnutls_x509_trust_list_add_system_trust`\n\n- `gnutls_certificate_set_x509_system_trust`\n\n- `gnutls_certificate_set_x509_crl_mem`\n\n- `gnutls_certificate_set_x509_trust_mem`\n\n- `gnutls_x509_trust_list_add_trust_file`\n\n- `gnutls_certificate_set_x509_crl_file`\n\n- `gnutls_certificate_set_x509_trust_file`\n\n- `gnutls_x509_trust_list_add_trust_dir`\n\n- `gnutls_certificate_set_x509_trust_dir`\n\n- `gnutls_x509_trust_list_remove_trust_mem`\n\n- `gnutls_x509_trust_list_remove_trust_file`\n\n- `gnutls_x509_trust_list_verify_crt2`\n\n- `gnutls_x509_cert_verify_peers`\n\n- `gnutls_certificate_verify_peers`\n\n- `gnutls_certificate_verify_peers2`\n\n- `gnutls_certificate_verify_peers3`\n\n- `gnutls_pkcs7_verify`\n\n- `gnutls_ocsp_resp_verify`\n\n- `gnutls_x509_trust_list_verify_crt`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2024-25062", - "name": "CVE-2024-25062", - "shortDescription": { - "text": "Scanner for CVE-2024-25062" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following functions are called:\n\n* `xmlValidatePopElement()`\n* `xmlTextReaderClose()`\n* `xmlFreeTextReader() `\n* `xmlTextReaderRead()`\n* `xmlSchemaValidateDoc()`", - "markdown": "The scanner checks whether any of the following functions are called:\n\n* `xmlValidatePopElement()`\n* `xmlTextReaderClose()`\n* `xmlFreeTextReader() `\n* `xmlTextReaderRead()`\n* `xmlSchemaValidateDoc()`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2024-28182", - "name": "CVE-2024-28182", - "shortDescription": { - "text": "Scanner for CVE-2024-28182" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "applicable", - "conclusion": "negative" - } - }, - { - "id": "applic_CVE-2024-2961", - "name": "CVE-2024-2961", - "shortDescription": { - "text": "Scanner for CVE-2024-2961" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2024-33600", - "name": "CVE-2024-33600", - "shortDescription": { - "text": "Scanner for CVE-2024-33600" - }, - "fullDescription": { - "text": "The scanner checks whether the `nscd` binary exists on the machine.", - "markdown": "The scanner checks whether the `nscd` binary exists on the machine." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2024-33599", - "name": "CVE-2024-33599", - "shortDescription": { - "text": "Scanner for CVE-2024-33599" - }, - "fullDescription": { - "text": "The scanner checks whether the `nscd` binary exists on the machine.", - "markdown": "The scanner checks whether the `nscd` binary exists on the machine." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2024-4741", - "name": "CVE-2024-4741", - "shortDescription": { - "text": "Scanner for CVE-2024-4741" - }, - "fullDescription": { - "text": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called.", - "markdown": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called." - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2023-31484", - "name": "CVE-2023-31484", - "shortDescription": { - "text": "Scanner for CVE-2023-31484" - }, - "fullDescription": { - "text": "The scanner checks whether a script (either bash or perl) installs a package through the `CPAN.pm` module.", - "markdown": "The scanner checks whether a script (either bash or perl) installs a package through the `CPAN.pm` module." - }, - "properties": { - "applicability": "undetermined", - "conclusion": "private" - } - }, - { - "id": "applic_CVE-2023-49464", - "name": "CVE-2023-49464", - "shortDescription": { - "text": "Scanner for CVE-2023-49464" - }, - "fullDescription": { - "text": "The scanner checks for two conditions:\n\n1. The `libheif.so` binary was compiled with the vulnerable setting `-DWITH_UNCOMPRESSED_CODEC=ON`. \n\n2. Any of the following vulnerable functions are called:\n\n* `HeifContext::Image::get_luma_bits_per_pixel`\n* `HeifContext::decode_full_grid_image`\n* `HeifFile::get_luma_bits_per_pixel_from_configuration`\n* `UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci`\n* `heif_image_handle_get_luma_bits_per_pixel`", - "markdown": "The scanner checks for two conditions:\n\n1. The `libheif.so` binary was compiled with the vulnerable setting `-DWITH_UNCOMPRESSED_CODEC=ON`. \n\n2. Any of the following vulnerable functions are called:\n\n* `HeifContext::Image::get_luma_bits_per_pixel`\n* `HeifContext::decode_full_grid_image`\n* `HeifFile::get_luma_bits_per_pixel_from_configuration`\n* `UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci`\n* `heif_image_handle_get_luma_bits_per_pixel`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2024-6119", - "name": "CVE-2024-6119", - "shortDescription": { - "text": "Scanner for CVE-2024-6119" - }, - "fullDescription": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`", - "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive", - "security-severity": "6.9" - } - }, - { - "id": "applic_CVE-2019-1010022", - "name": "CVE-2019-1010022", - "shortDescription": { - "text": "Scanner for uncovered CVE-2019-1010022" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2019-3815", - "name": "CVE-2019-3815", - "shortDescription": { - "text": "Scanner for uncovered CVE-2019-3815" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-6228", - "name": "CVE-2023-6228", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-6228" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-27102", - "name": "CVE-2023-27102", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-27102" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-26462", - "name": "CVE-2024-26462", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-26462" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-34459", - "name": "CVE-2024-34459", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-34459" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2010-4756", - "name": "CVE-2010-4756", - "shortDescription": { - "text": "Scanner for uncovered CVE-2010-4756" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2017-17740", - "name": "CVE-2017-17740", - "shortDescription": { - "text": "Scanner for uncovered CVE-2017-17740" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-31437", - "name": "CVE-2023-31437", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-31437" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-4039", - "name": "CVE-2023-4039", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-4039" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-25269", - "name": "CVE-2024-25269", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-25269" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-2379", - "name": "CVE-2024-2379", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-2379" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-26458", - "name": "CVE-2024-26458", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-26458" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-6237", - "name": "CVE-2023-6237", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-6237" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2017-9117", - "name": "CVE-2017-9117", - "shortDescription": { - "text": "Scanner for uncovered CVE-2017-9117" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2022-3219", - "name": "CVE-2022-3219", - "shortDescription": { - "text": "Scanner for uncovered CVE-2022-3219" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-1916", - "name": "CVE-2023-1916", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-1916" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-37371", - "name": "CVE-2024-37371", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-37371" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2013-4392", - "name": "CVE-2013-4392", - "shortDescription": { - "text": "Scanner for uncovered CVE-2013-4392" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-2908", - "name": "CVE-2023-2908", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-2908" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-6277", - "name": "CVE-2023-6277", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-6277" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2017-17973", - "name": "CVE-2017-17973", - "shortDescription": { - "text": "Scanner for uncovered CVE-2017-17973" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2022-27943", - "name": "CVE-2022-27943", - "shortDescription": { - "text": "Scanner for uncovered CVE-2022-27943" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-4603", - "name": "CVE-2024-4603", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-4603" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-45491", - "name": "CVE-2024-45491", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-45491" - }, - "fullDescription": { - "text": "The scanner checks whether the `xmlwf` CLI tool exists or if the vulnerable function `XML_ExternalEntityParserCreate()` is called.\n\nThis CVE is applicable only when the platform is 32bit. The scanner currently does not check for this condition.", - "markdown": "The scanner checks whether the `xmlwf` CLI tool exists or if the vulnerable function `XML_ExternalEntityParserCreate()` is called.\n\nThis CVE is applicable only when the platform is 32bit. The scanner currently does not check for this condition." - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-7006", - "name": "CVE-2024-7006", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-7006" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-7008", - "name": "CVE-2023-7008", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-7008" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2015-3276", - "name": "CVE-2015-3276", - "shortDescription": { - "text": "Scanner for uncovered CVE-2015-3276" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-45918", - "name": "CVE-2023-45918", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-45918" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2019-9192", - "name": "CVE-2019-9192", - "shortDescription": { - "text": "Scanner for uncovered CVE-2019-9192" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-28757", - "name": "CVE-2024-28757", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-28757" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-32570", - "name": "CVE-2023-32570", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-32570" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2009-4487", - "name": "CVE-2009-4487", - "shortDescription": { - "text": "Scanner for uncovered CVE-2009-4487" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2011-0283", - "name": "CVE-2011-0283", - "shortDescription": { - "text": "Scanner for uncovered CVE-2011-0283" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-4641", - "name": "CVE-2023-4641", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-4641" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2012-2131", - "name": "CVE-2012-2131", - "shortDescription": { - "text": "Scanner for uncovered CVE-2012-2131" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2011-4116", - "name": "CVE-2011-4116", - "shortDescription": { - "text": "Scanner for uncovered CVE-2011-4116" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2017-9937", - "name": "CVE-2017-9937", - "shortDescription": { - "text": "Scanner for uncovered CVE-2017-9937" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-3164", - "name": "CVE-2023-3164", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-3164" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-38949", - "name": "CVE-2024-38949", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-38949" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-45492", - "name": "CVE-2024-45492", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-45492" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2019-1010024", - "name": "CVE-2019-1010024", - "shortDescription": { - "text": "Scanner for uncovered CVE-2019-1010024" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-0727", - "name": "CVE-2024-0727", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-0727" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-37370", - "name": "CVE-2024-37370", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-37370" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-5678", - "name": "CVE-2023-5678", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-5678" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2016-2781", - "name": "CVE-2016-2781", - "shortDescription": { - "text": "Scanner for uncovered CVE-2016-2781" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-31439", - "name": "CVE-2023-31439", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-31439" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-51792", - "name": "CVE-2023-51792", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-51792" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2021-4214", - "name": "CVE-2021-4214", - "shortDescription": { - "text": "Scanner for uncovered CVE-2021-4214" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-22365", - "name": "CVE-2024-22365", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-22365" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-31438", - "name": "CVE-2023-31438", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-31438" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2018-10126", - "name": "CVE-2018-10126", - "shortDescription": { - "text": "Scanner for uncovered CVE-2018-10126" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-33602", - "name": "CVE-2024-33602", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-33602" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2022-1210", - "name": "CVE-2022-1210", - "shortDescription": { - "text": "Scanner for uncovered CVE-2022-1210" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-3618", - "name": "CVE-2023-3618", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-3618" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-26966", - "name": "CVE-2023-26966", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-26966" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-6780", - "name": "CVE-2023-6780", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-6780" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2015-9019", - "name": "CVE-2015-9019", - "shortDescription": { - "text": "Scanner for uncovered CVE-2015-9019" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2010-4665", - "name": "CVE-2010-4665", - "shortDescription": { - "text": "Scanner for uncovered CVE-2010-4665" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-39615", - "name": "CVE-2023-39615", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-39615" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2017-16232", - "name": "CVE-2017-16232", - "shortDescription": { - "text": "Scanner for uncovered CVE-2017-16232" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2019-1010025", - "name": "CVE-2019-1010025", - "shortDescription": { - "text": "Scanner for uncovered CVE-2019-1010025" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-26461", - "name": "CVE-2024-26461", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-26461" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-6129", - "name": "CVE-2023-6129", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-6129" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-1580", - "name": "CVE-2024-1580", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-1580" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-29659", - "name": "CVE-2023-29659", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-29659" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-31486", - "name": "CVE-2023-31486", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-31486" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-29383", - "name": "CVE-2023-29383", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-29383" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2020-15719", - "name": "CVE-2020-15719", - "shortDescription": { - "text": "Scanner for uncovered CVE-2020-15719" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2017-5563", - "name": "CVE-2017-5563", - "shortDescription": { - "text": "Scanner for uncovered CVE-2017-5563" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-39804", - "name": "CVE-2023-39804", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-39804" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-2236", - "name": "CVE-2024-2236", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-2236" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2022-3636", - "name": "CVE-2022-3636", - "shortDescription": { - "text": "Scanner for uncovered CVE-2022-3636" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-46219", - "name": "CVE-2023-46219", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-46219" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2022-48303", - "name": "CVE-2022-48303", - "shortDescription": { - "text": "Scanner for uncovered CVE-2022-48303" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-5981", - "name": "CVE-2023-5981", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-5981" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-2398", - "name": "CVE-2024-2398", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-2398" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2011-3389", - "name": "CVE-2011-3389", - "shortDescription": { - "text": "Scanner for uncovered CVE-2011-3389" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-33601", - "name": "CVE-2024-33601", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-33601" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2019-1010023", - "name": "CVE-2019-1010023", - "shortDescription": { - "text": "Scanner for uncovered CVE-2019-1010023" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2007-5686", - "name": "CVE-2007-5686", - "shortDescription": { - "text": "Scanner for uncovered CVE-2007-5686" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-2511", - "name": "CVE-2024-2511", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-2511" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-28834", - "name": "CVE-2024-28834", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-28834" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-47471", - "name": "CVE-2023-47471", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-47471" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-45322", - "name": "CVE-2023-45322", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-45322" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-7347", - "name": "CVE-2024-7347", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-7347" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2017-14159", - "name": "CVE-2017-14159", - "shortDescription": { - "text": "Scanner for uncovered CVE-2017-14159" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-3576", - "name": "CVE-2023-3576", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-3576" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-25433", - "name": "CVE-2023-25433", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-25433" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-28085", - "name": "CVE-2024-28085", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-28085" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2018-20796", - "name": "CVE-2018-20796", - "shortDescription": { - "text": "Scanner for uncovered CVE-2018-20796" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-50495", - "name": "CVE-2023-50495", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-50495" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-38950", - "name": "CVE-2024-38950", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-38950" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-46218", - "name": "CVE-2023-46218", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-46218" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-5535", - "name": "CVE-2024-5535", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-5535" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-6779", - "name": "CVE-2023-6779", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-6779" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-28835", - "name": "CVE-2024-28835", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-28835" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2023-52426", - "name": "CVE-2023-52426", - "shortDescription": { - "text": "Scanner for uncovered CVE-2023-52426" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2024-7264", - "name": "CVE-2024-7264", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-7264" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2017-18018", - "name": "CVE-2017-18018", - "shortDescription": { - "text": "Scanner for uncovered CVE-2017-18018" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, - { - "id": "applic_CVE-2018-6829", - "name": "CVE-2018-6829", - "shortDescription": { - "text": "Scanner for uncovered CVE-2018-6829" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } - }, + "issue_id": "XRAY-632747", + "references": [ + "https://openssl-library.org/news/secadv/20240903.txt", + "https://github.com/openssl/openssl/commit/621f3729831b05ee828a3203eddb621d014ff2b2", + "https://github.com/openssl/openssl/commit/05f360d9e849a1b277db628f1f13083a7f8dd04f", + "https://security-tracker.debian.org/tracker/CVE-2024-6119", + "https://github.com/openssl/openssl/commit/7dfcee2cd2a63b2c64b9b4b0850be64cb695b0a0", + "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" + ], + "extended_information": { + "short_description": "Out of bounds read in OpenSSL clients can lead to denial of service when using non-default TLS verification options and connecting to malicious TLS servers", + "jfrog_research_severity": "Medium", + "jfrog_research_severity_reasons": [ { - "id": "applic_CVE-2005-2541", - "name": "CVE-2005-2541", - "shortDescription": { - "text": "Scanner for uncovered CVE-2005-2541" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } + "name": "The issue has an exploit published", + "description": "The fix commit contains PoC certificates that trigger the denial of service issue" }, { - "id": "applic_CVE-2024-2004", - "name": "CVE-2024-2004", - "shortDescription": { - "text": "Scanner for uncovered CVE-2024-2004" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker must make the victim client connect to their malicious TLS server, in order to serve the malformed TLS certificate. The victim client must use OpenSSL and must enable non-default certificate verification options, either -\n\n* DNS verification - by using `X509_VERIFY_PARAM_set1_host` or `X509_check_host`\n* Email verification - by using ` X509_VERIFY_PARAM_set1_email` or `X509_check_email`", + "is_positive": true }, { - "id": "applic_CVE-2019-19882", - "name": "CVE-2019-19882", - "shortDescription": { - "text": "Scanner for uncovered CVE-2019-19882" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "not_covered" - } + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Denial of service of a TLS clients only. This out of bounds read cannot lead to data disclosure.", + "is_positive": true } - ], - "version": "1.0" + ] } }, - "invocations": [ - { - "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", - "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1725978580-3584350251/Applicability_1725978580/config.yaml" - ], - "executionSuccessful": true, - "workingDirectory": { - "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1725978503-2625964325/image.tar" - } - } - ], - "results": [ - { - "ruleId": "applic_CVE-2011-3374", - "kind": "pass", - "message": { - "text": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." - } - }, - { - "ruleId": "applic_CVE-2013-0337", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the Nginx log files (`error.log` and `access.log`) is a symbolic link. If both files are symbolic links that point to `\\dev\\*` path, the vulnerability is not relevant, thus not applicable. If one of the log files is not a symbolic link, the vulnerability is applicable." - } - }, - { - "ruleId": "applic_CVE-2018-5709", - "kind": "pass", - "message": { - "text": "This CVE has no security impact, hence it is never applicable.\nOriginally, the vulnerability was mistakenly reported as an integer overflow, but it is actually an integer truncation.\nThe issue does not affect any other data allocated close to the 16-bit integer in question. Furthermore, a negative value of the 16-bit integer does not impact the flow of the program in any meaningful way." - } - }, - { - "ruleId": "applic_CVE-2024-5171", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the vulnerable functions are called:\n\n* `aom_img_alloc()`\n\n* `aom_img_wrap()`\n\n* `aom_img_alloc_with_border()`" - } - }, - { - "ruleId": "applic_CVE-2023-39616", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable function `aom_codec_encode` is called.\n\nIn order for the vulnerability to be fully applicable, the vulnerable code must also call the `aom_codec_enc_init` function with the 3rd argument struct (`config`) being set with `dropframe_thresh` == 1. This additional condition is currently not checked by the scanner.\n\nNote that the vulnerability is also exploitable through the CLI tool `aomenc` under rare conditions. However - exploitation of the CLI tool will cause it to simply crash, which has no security impact (crashing of a forked client process)." - } - }, - { - "ruleId": "applic_CVE-2022-0563", - "kind": "pass", - "message": { - "text": "The scanner checks whether the `chfs` and `chfn` CLI utilities are compiled with the vulnerable `readline` library." - } - }, - { - "ruleId": "applic_CVE-2023-27103", - "kind": "pass", - "message": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" - } - }, - { - "ruleId": "applic_CVE-2023-49465", - "kind": "pass", - "message": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" - } - }, - { - "ruleId": "applic_CVE-2023-49467", - "kind": "pass", - "message": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" - } - }, - { - "ruleId": "applic_CVE-2023-49468", - "kind": "pass", - "message": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `de265_new_decoder`\n* `de265_decode`\n* `de265_decode_data`" - } - }, - { - "ruleId": "applic_CVE-2023-52425", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the next functions are called:\n\n* `XML_Parse()`\n* `XML_ParseBuffer()`\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: The vulnerable functions are used to parse an attacker-controlled file by chunks." - } - }, - { - "ruleId": "applic_CVE-2024-45490", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `XML_Parse()`\n- `XML_ParseBuffer()`\n\nAn additional condition, which the scanner currently does not check, is that the `len` parameter which is passed to those functions is user-controlled." - } - }, - { - "ruleId": "applic_CVE-2023-26965", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable `tiffcrop` binary is present in the image.\n\nNote that the scanner does not check whether `tiffcrop` is invoked with arbitrary image files." - } - }, - { - "ruleId": "applic_CVE-2023-2953", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the following vulnerable functions are used:\n\n- `ldif_open_url`\n- `ldif_fetch_url`\n- `ldif_parse_line2`\n- `ldif_parse_line`\n- `ldap_parse_ldif_record_x`\n- `ldap_parse_ldif_record`\n- `ldif_read_record`\n- `slapi_str2entry`" - } - }, - { - "ruleId": "applic_CVE-2023-40745", - "kind": "pass", - "message": { - "text": "" - } - }, - { - "ruleId": "applic_CVE-2023-41175", - "kind": "pass", - "message": { - "text": "" - } - }, - { - "ruleId": "applic_CVE-2023-43887", - "kind": "pass", - "message": { - "text": "The scanner checks for the presence of a binary related to `libde265` on the scanned artifact, specifically, any file ending with `dec265`." - } - }, - { - "ruleId": "applic_CVE-2023-44487", - "kind": "pass", - "message": { - "text": "The scanner checks for each vendor listed here:\n\n* Tomcat: configuration enables HTTP/2 either through the XML file or Java's `addUpgradeProtocol()` method.\n* Jetty: HTTP/2 enabled through `HTTP2CServerConnectionFactory`/`HTTP2ServerConnectionFactory` class initialization. Note: it also checks whether `jenkins` enables http/2 through its configuration.\n* Nginx: check whether one of the HTTP configurations is enabling http/2.\nNote: the following parameters should be configured properly to make the vulnerability not applicable:\n`keepalive_requests` should be kept at the default setting of 1000 requests\n`http2_max_concurrent_streams` should be kept at the default setting of 128 streams\n`limit_conn and limit_req` should be set `with a reasonable setting balancing application performance and security`. \n* Netty: check whether the `http2` codec classes are used in a java class\n* NodeJS: check whether the `http2.createSecureServer()` is used\n* NGHttp2: check whether a web server is instantiated through one of the symbols `nghttp2_session_server_new` or `listen_and_serve`.\n* Go: check whether a server is instantiated through the `net/http` or `net/http2` packages" - } - }, - { - "ruleId": "applic_CVE-2023-45853", - "kind": "pass", - "message": { - "text": "The scanner checks if any of the following functions are called:\n\n- `zipOpenNewFileInZip`\n- `zipOpenNewFileInZip_64`\n- `zipOpenNewFileInZip2`\n- `zipOpenNewFileInZip2_64`\n- `zipOpenNewFileInZip3`\n- `zipOpenNewFileInZip3_64`\n- `zipOpenNewFileInZip4`\n- `zipOpenNewFileInZip4_64`" - } - }, - { - "ruleId": "applic_CVE-2023-47038", - "kind": "pass", - "message": { - "text": "This CVE has no security impact (hence it is never applicable) as one of its prerequisites is arbitrary execution of Perl code, making any security impact of exploiting the vulnerability negligible since arbitrary code execution has already occurred." - } - }, - { - "ruleId": "applic_CVE-2023-49460", - "kind": "pass", - "message": { - "text": "The scanner checks if the `libheif` binary was compiled with the vulnerable setting `-DWITH_UNCOMPRESSED_CODEC=ON` and if the vulnerable function `UncompressedImageCodec::decode_uncompressed_image` is called." - } - }, - { - "ruleId": "applic_CVE-2023-49463", - "kind": "pass", - "message": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `read_exif_orientation_tag`\n\n* `modify_exif_orientation_tag_if_it_exists`" - } - }, - { - "ruleId": "applic_CVE-2023-49462", - "kind": "pass", - "message": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n* `read_exif_orientation_tag`\n\n* `modify_exif_orientation_tag_if_it_exists`" - } - }, - { - "ruleId": "applic_CVE-2023-52355", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the following functions are called:\n\n- `TIFFRasterScanlineSize64()`\n- `TIFFRasterScanlineSize()`" + { + "cves": [ + { + "cve": "CVE-2024-38428", + "cvss_v3_score": "9.1", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N", + "cwe": [ + "CWE-436" + ], + "cwe_details": { + "CWE-436": { + "name": "Interpretation Conflict", + "description": "Product A handles inputs or steps differently than Product B, which causes A to perform incorrect actions based on its perception of B's state." + } + } + } + ], + "summary": "url.c in GNU Wget through 1.24.5 mishandles semicolons in the userinfo subcomponent of a URI, and thus there may be insecure behavior in which data that was supposed to be in the userinfo subcomponent is misinterpreted to be part of the host subcomponent.", + "severity": "Critical", + "components": { + "deb://debian:bookworm:wget:1.21.3-1+b1": { + "impact_paths": [ + [ + { + "component_id": "docker://platform.jfrog.io/swamp-docker/swamp:latest" + }, + { + "component_id": "generic://sha256:f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595/sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "full_path": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + }, + { + "component_id": "deb://debian:bookworm:wget:1.21.3-1+b1", + "full_path": "wget:1.21.3-1+b1" + } + ] + ] } }, - { - "ruleId": "applic_CVE-2023-52356", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the following functions are called:\n\n- `TIFFReadRGBATileExt()` \n- `TIFFReadRGBATile()`" + "issue_id": "XRAY-606103", + "references": [ + "https://git.savannah.gnu.org/cgit/wget.git/commit/?id=ed0c7c7e0e8f7298352646b2fd6e06a11e242ace", + "https://lists.gnu.org/archive/html/bug-wget/2024-06/msg00005.html", + "https://security-tracker.debian.org/tracker/CVE-2024-38428" + ] + }, + { + "summary": "Malicious package cors.js for Node.js", + "severity": "Critical", + "components": { + "npm://cors.js:0.0.1-security": { + "impact_paths": [ + [ + { + "component_id": "docker://platform.jfrog.io/swamp-docker/swamp:latest" + }, + { + "component_id": "generic://sha256:ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f/sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar", + "full_path": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" + }, + { + "component_id": "npm://cors.js:0.0.1-security", + "full_path": "usr/src/app/node_modules/cors.js/package.json" + } + ] + ] } }, - { - "ruleId": "applic_CVE-2023-5363", - "kind": "pass", - "message": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n- `EVP_EncryptInit_ex2`\n- `EVP_DecryptInit_ex2`\n- `EVP_CipherInit_ex2`" + "issue_id": "XRAY-264729", + "references": [ + "https://registry.npmjs.com" + ], + "extended_information": { + "short_description": "Malicious package cors.js for Node.js", + "full_description": "The package cors.js for Node.js contains malicious code that installs a persistent connectback shell. The package is typosquatting the popular `cors` package. When installed, the package opens a connectback shell to the hardcoded host `107.175.32.229` on TCP port 56173. The malicious payload achieves persistency by installing a cron job that repeats every 10 seconds - `*/10 * * * * *`", + "jfrog_research_severity": "Critical", + "remediation": "As with any malware, the malicious package must be completely removed, and steps must be taken care to remediate the damage that was done by the malicious package -\n\n##### Removing the malicious package\n\nRun `npm uninstall cors.js`\n\n##### Refreshing stolen credentials\n\nMany malicious packages steal stored user credentials, focusing on the following -\n\n* [Browser autocomplete](https://jfrog.com/blog/malicious-pypi-packages-stealing-credit-cards-injecting-code/) data, such as saved passwords and credit cards\n* [Environment variables](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/) passed to the malicious code\n* [Stored Discord tokens](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)\n* AWS / GitHub credentials stored in cleartext files\n\nIt is highly recommended to change or revoke data that is stored in the infected machine at those locations\n\n##### Stopping malicious processes\n\nMany malicious packages start malicious processes such as [connectback shells](https://jfrog.com/blog/jfrog-discloses-3-remote-access-trojans-in-pypi/) or crypto-miners. Search for any unfamiliar processes that consume a large amount of CPU or a large amount of network traffic, and stop them. On Windows, this can be facilitated with [Sysinternals Process Explorer](https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer).\n\n##### Removing installed backdoors\n\nMany malicious packages install themselves as a [persistent backdoor](https://jfrog.com/blog/npm-supply-chain-attack-targets-german-based-companies/), in order to guarantee the malicious code survives a reboot. Search for any unfamiliar binaries set to be run on startup, and remove them. On Windows, this can be facilitated with [Sysinternals Autoruns](https://docs.microsoft.com/en-us/sysinternals/downloads/autoruns).\n\n##### Defining an Xray policy that blocks downloads of Artifacts with malicious packages\n\nIt is possible to [create an Xray policy](https://www.jfrog.com/confluence/display/JFROG/Creating+Xray+Policies+and+Rules) that will not allow artifacts with identified malicious packages to be downloaded from Artifactory. To create such a policy, add a new `Security` policy and set `Minimal Severity` to `Critical`. Under `Automatic Actions` check the `Block Download` action.\n\n##### Contacting the JFrog Security Research team for additional information\n\nOptionally, if you are unsure of the full impact of the malicious package and wish to get more details, the JFrog Security Research team can help you assess the potential damage from the installed malicious package.\n\nPlease contact us at research@jfrog.com with details of the affected artifact and the name of the identified malicious package." + } + }, + { + "cves": [ + { + "cve": "CVE-2024-45490", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-611" + ], + "cwe_details": { + "CWE-611": { + "name": "Improper Restriction of XML External Entity Reference", + "description": "The product processes an XML document that can contain XML entities with URIs that resolve to documents outside of the intended sphere of control, causing the product to embed incorrect documents into its output." + } + } + } + ], + "summary": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", + "severity": "Critical", + "components": { + "deb://debian:bookworm:libexpat1:2.5.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://platform.jfrog.io/swamp-docker/swamp:latest" + }, + { + "component_id": "generic://sha256:20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1/sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "full_path": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + }, + { + "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", + "full_path": "libexpat1:2.5.0-1" + } + ] + ] } }, - { - "properties": { - "metadata": "", - "tokenValidation": "" - }, - "ruleId": "applic_CVE-2023-6246", - "message": { - "text": "The vulnerable function `syslog` is called in a suid/guid file" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///usr/bin/chage" - }, - "region": { - "snippet": { - "text": "" + "issue_id": "XRAY-632613", + "references": [ + "https://github.com/libexpat/libexpat/issues/887", + "https://security-tracker.debian.org/tracker/CVE-2024-45490", + "https://github.com/libexpat/libexpat/pull/890" + ] + }, + { + "cves": [ + { + "cve": "CVE-2024-45492", + "cvss_v3_score": "9.8", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "CWE-190" + ], + "cwe_details": { + "CWE-190": { + "name": "Integer Overflow or Wraparound", + "description": "The product performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.", + "categories": [ + { + "category": "2023 CWE Top 25", + "rank": "14" } - } + ] } } - ] - }, - { - "properties": { - "metadata": "", - "tokenValidation": "" - }, - "ruleId": "applic_CVE-2023-6246", - "message": { - "text": "The vulnerable function `syslog` is called in a suid/guid file" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///usr/bin/chfn" + } + ], + "summary": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", + "severity": "Critical", + "components": { + "deb://debian:bookworm:libexpat1:2.5.0-1": { + "impact_paths": [ + [ + { + "component_id": "docker://platform.jfrog.io/swamp-docker/swamp:latest" }, - "region": { - "snippet": { - "text": "" - } + { + "component_id": "generic://sha256:20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1/sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "full_path": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + }, + { + "component_id": "deb://debian:bookworm:libexpat1:2.5.0-1", + "full_path": "libexpat1:2.5.0-1" } - } - } - ] + ] + ] + } }, - { - "properties": { - "metadata": "", - "tokenValidation": "" - }, - "ruleId": "applic_CVE-2023-6246", - "message": { - "text": "The vulnerable function `syslog` is called in a suid/guid file" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///usr/bin/chsh" + "issue_id": "XRAY-632612", + "references": [ + "https://github.com/libexpat/libexpat/issues/889", + "https://security-tracker.debian.org/tracker/CVE-2024-45492", + "https://github.com/libexpat/libexpat/pull/892" + ] + }, + { + "cves": [ + { + "cve": "CVE-2023-51767", + "cvss_v3_score": "7.0", + "cvss_v3_vector": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H", + "cwe": [ + "NVD-CWE-Other" + ] + } + ], + "summary": "OpenSSH through 9.6, when common types of DRAM are used, might allow row hammer attacks (for authentication bypass) because the integer value of authenticated in mm_answer_authpassword does not resist flips of a single bit. NOTE: this is applicable to a certain threat model of attacker-victim co-location in which the attacker has user privileges.", + "severity": "Low", + "components": { + "deb://debian:bookworm:openssh-client:1:9.2p1-2+deb12u3": { + "impact_paths": [ + [ + { + "component_id": "docker://platform.jfrog.io/swamp-docker/swamp:latest" }, - "region": { - "snippet": { - "text": "" - } + { + "component_id": "generic://sha256:20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1/sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "full_path": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + }, + { + "component_id": "deb://debian:bookworm:openssh-client:1:9.2p1-2+deb12u3", + "full_path": "openssh-client:1:9.2p1-2+deb12u3" } - } - } - ] + ] + ] + } }, - { - "properties": { - "metadata": "", - "tokenValidation": "" - }, - "ruleId": "applic_CVE-2023-6246", - "message": { - "text": "The vulnerable function `syslog` is called in a suid/guid file" - }, - "locations": [ + "issue_id": "XRAY-585612", + "references": [ + "https://arxiv.org/abs/2309.02545", + "https://github.com/openssh/openssh-portable/blob/8241b9c0529228b4b86d88b1a6076fb9f97e4a99/monitor.c#L878", + "https://github.com/openssh/openssh-portable/blob/8241b9c0529228b4b86d88b1a6076fb9f97e4a99/auth-passwd.c#L77", + "https://bugzilla.redhat.com/show_bug.cgi?id=2255850", + "https://security-tracker.debian.org/tracker/CVE-2023-51767", + "https://ubuntu.com/security/CVE-2023-51767", + "https://security.netapp.com/advisory/ntap-20240125-0006/", + "https://access.redhat.com/security/cve/CVE-2023-51767" + ], + "extended_information": { + "short_description": "The RowHammer fault injection attack can theoretically lead to local authentication bypass in OpenSSH.", + "full_description": "[OpenSSH](https://www.openssh.com/) is a popular open-source implementation of the SSH (Secure Shell) protocol, providing encrypted communication over a network.\nIt was discovered that the OpenSSH authentication logic can be susceptible in some cases to a side-channel fault injection attack. The attack can theoretically be carried out by a local attacker which eventually bypass OpenSSH authentication mechanism.\n\nThis vulnerability currently lacks widely known published exploits, and its exploitation is considered highly complex. The intricacies of the attack, combined with the absence of well-documented exploits, contribute to the difficulty in achieving successful exploitation. Furthermore, it's essential to note that the susceptibility to this vulnerability is hardware-dependent, and the success of an attack relies on probabilities associated with the specific hardware configuration. \n\nThe vulnerability is theoretically exploitable by several different ways, the only two published ways are:\n\nIn the OpenSSH function `mm_answer_authpassword()`, a stack variable `authenticated`, is assigned to the value of the function `auth_password()` which returns 1/0 and then returned. If the value of `authenticated` is 1, the SSH connection will be established. Since `authenticated` is stored on the stack, therefore in DRAM, a local attacker could flip this 32-bit integer least significant bit, thus, bypass authentication.\n\nAnother possible exploit is the `result` stack variable in `auth_password()` function. It is initialized to 0 and set to 1 if the password is correct. \nSimilarly to the previous method, this attack requires a single bit flip of the `result` variable in order for the function to return 1 and bypass the authentication.\n\nAttackers can trigger the vulnerability via a RowHammer fault injection. The Rowhammer bug is a hardware reliability issue in which an attacker repeatedly accesses (hammers) DRAM cells to cause unauthorized changes in physically adjacent memory locations.\nSimply put:\n\n* A specific register value(`authenticated`/`result` value) is pushed onto the stack during program execution. \n* The stack, where the register value is stored, is identified to be located in a memory row susceptible to bit flips (flippable row) due to the RowHammer vulnerability in DRAM.\n* The attacker performs a series of rapid and repeated memory accesses to the adjacent rows of the flippable row in the DRAM. This repeated access exploits the RowHammer vulnerability, inducing bit flips in the targeted flippable row.\n* Due to the RowHammer effect, bit flips occur in the flippable row, potentially corrupting the data stored there.\n* After inducing bit flips in the flippable row, the attacker manipulates the program's control flow to pop the corrupted value from the stack into a register.\n* The register now holds a value that has been corrupted through the RowHammer attack. Now the `authenticated`/`result` variables hold this corrupted value thus it can lead to authentication bypass, as it may impact the control flow in a way advantageous to the attacker.", + "jfrog_research_severity": "Low", + "jfrog_research_severity_reasons": [ { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///usr/bin/expiry" - }, - "region": { - "snippet": { - "text": "" - } - } - } + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The vulnerability depends on the OS and hardware. It was only evaluated in one test environment, therefore results for other conditions might differ. The attacker must be extremely familiar with the details of the exploited system (ex. know the exact hardware which is running the OS).", + "is_positive": true + }, + { + "name": "The issue can only be exploited by an attacker that can execute code on the vulnerable machine (excluding exceedingly rare circumstances)", + "is_positive": true + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Exploitation is extremely non-trivial (even theoretically), no public exploits have been published.", + "is_positive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The vulnerability's attack complexity is significantly higher than what the CVSS represents.", + "is_positive": true } ] - }, - { - "properties": { - "metadata": "", - "tokenValidation": "" - }, - "ruleId": "applic_CVE-2023-6246", - "message": { - "text": "The vulnerable function `syslog` is called in a suid/guid file" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///usr/bin/gpasswd" + } + }, + { + "cves": [ + { + "cve": "CVE-2011-3374", + "cvss_v2_score": "4.3", + "cvss_v2_vector": "CVSS:2.0/AV:N/AC:M/Au:N/C:N/I:P/A:N", + "cvss_v3_score": "3.7", + "cvss_v3_vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N", + "cwe": [ + "CWE-347" + ], + "cwe_details": { + "CWE-347": { + "name": "Improper Verification of Cryptographic Signature", + "description": "The product does not verify, or incorrectly verifies, the cryptographic signature for data." + } + } + } + ], + "summary": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", + "severity": "Low", + "components": { + "deb://debian:bookworm:apt:2.6.1": { + "impact_paths": [ + [ + { + "component_id": "docker://platform.jfrog.io/swamp-docker/swamp:latest" }, - "region": { - "snippet": { - "text": "" - } + { + "component_id": "generic://sha256:cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e/sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", + "full_path": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + }, + { + "component_id": "deb://debian:bookworm:apt:2.6.1", + "full_path": "apt:2.6.1" } - } - } - ] - }, - { - "properties": { - "metadata": "", - "tokenValidation": "" - }, - "ruleId": "applic_CVE-2023-6246", - "message": { - "text": "The vulnerable function `syslog` is called in a suid/guid file" + ] + ] }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///usr/bin/newgrp" + "deb://debian:bookworm:libapt-pkg6.0:2.6.1": { + "impact_paths": [ + [ + { + "component_id": "docker://platform.jfrog.io/swamp-docker/swamp:latest" }, - "region": { - "snippet": { - "text": "" - } + { + "component_id": "generic://sha256:cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e/sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", + "full_path": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + }, + { + "component_id": "deb://debian:bookworm:libapt-pkg6.0:2.6.1", + "full_path": "libapt-pkg6.0:2.6.1" } - } - } - ] + ] + ] + } }, - { - "properties": { - "metadata": "", - "tokenValidation": "" - }, - "ruleId": "applic_CVE-2023-6246", - "message": { - "text": "The vulnerable function `syslog` is called in a suid/guid file" - }, - "locations": [ + "issue_id": "XRAY-34417", + "references": [ + "https://people.canonical.com/~ubuntu-security/cve/2011/CVE-2011-3374.html", + "https://seclists.org/fulldisclosure/2011/Sep/221", + "https://ubuntu.com/security/CVE-2011-3374", + "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=642480", + "https://access.redhat.com/security/cve/cve-2011-3374", + "https://snyk.io/vuln/SNYK-LINUX-APT-116518", + "https://security-tracker.debian.org/tracker/CVE-2011-3374" + ], + "extended_information": { + "short_description": "Improper signature validation in apt-key may enable Man-in-the-Middle attacks and result in code execution.", + "full_description": "`apt-key` is [`apt`](https://github.com/Debian/apt)'s key management utility, and is used to manage the keys that are used by `apt` to authenticate packages.\n\nA vulnerability in `apt-key`'s `net-update` function exists, in which [`GPG`](https://www.gnupg.org/) keys, that are used for signing packages and validating their authenticity, aren't validated correctly. The `net-update` function pulls the signing keys that should be added from an insecure location (`http://...`), exposing it to a Man-in-the-Middle attack in which malicious signing keys could be added to the system's keyring. This issue happens due to a vulnerability in the `add_keys_with_veirfy_against_master_keyring()` function, which allows adding signing keys without proper signature validation. \n\nThis vulnerability then potentially allows a malicious actor to perform a Man-in-the-Middle attack on a target, by making it validate malicious packages that were signed with the `GPG` signing key used by the attacker. Effectively, this means that `apt` can be duped to install malicious services and daemons with root privileges.\n\nThe conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man In The Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from [python-apt](https://pypi.org/project/python-apt/) Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.\n\nDo note that `apt-key` is **deprecated** and shouldn't be used, and in most Debian versions `ARCHIVE_KEYRING_URI` is not defined, making this vulnerability unexploitable in most Debian systems.", + "jfrog_research_severity": "High", + "jfrog_research_severity_reasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the python-apt Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", + "is_positive": true + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "This vulnerability is remotely exploitable when the applicability conditions apply." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Remote code execution is possible when the applicability conditions apply." + }, { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///usr/bin/passwd" + "name": "The issue has an exploit published", + "description": "The reporter of this issue has provided a GPG key that can be used for an actual attack, as well as a simple PoC example." + } + ], + "remediation": "##### Deployment mitigations\n\n* Dot not execute `apt-key` command, as it is deprecated.\n* Remove the URI configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`." + } + }, + { + "cves": [ + { + "cve": "CVE-2024-4741" + } + ], + "summary": "CVE-2024-4741", + "severity": "Unknown", + "components": { + "deb://debian:bookworm:libssl3:3.0.13-1~deb12u1": { + "impact_paths": [ + [ + { + "component_id": "docker://platform.jfrog.io/swamp-docker/swamp:latest" }, - "region": { - "snippet": { - "text": "" - } + { + "component_id": "generic://sha256:f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595/sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "full_path": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + }, + { + "component_id": "deb://debian:bookworm:libssl3:3.0.13-1~deb12u1", + "full_path": "libssl3:3.0.13-1~deb12u1" } - } - } - ] - }, - { - "properties": { - "metadata": "", - "tokenValidation": "" - }, - "ruleId": "applic_CVE-2023-6246", - "message": { - "text": "The vulnerable function `syslog` is called in a suid/guid file" + ] + ] }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///usr/bin/su" + "deb://debian:bookworm:openssl:3.0.13-1~deb12u1": { + "fixed_versions": [ + "[3.0.14-1~deb12u1]" + ], + "impact_paths": [ + [ + { + "component_id": "docker://platform.jfrog.io/swamp-docker/swamp:latest" }, - "region": { - "snippet": { - "text": "" - } + { + "component_id": "generic://sha256:f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595/sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "full_path": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + }, + { + "component_id": "deb://debian:bookworm:openssl:3.0.13-1~deb12u1", + "full_path": "openssl:3.0.13-1~deb12u1" + } + ] + ] + } + }, + "issue_id": "XRAY-603657", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-4741" + ] + } + ], + "component_id": "docker://platform.jfrog.io/swamp-docker/swamp:latest", + "package_type": "oci", + "status": "completed" + } + ] + }, + "jas_scans": { + "contextual_analysis": [ + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Applicability Scanner", + "rules": [ + { + "id": "applic_CVE-2024-6119", + "name": "CVE-2024-6119", + "shortDescription": { + "text": "Scanner for CVE-2024-6119" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`", + "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-45490", + "name": "CVE-2024-45490", + "shortDescription": { + "text": "Scanner for CVE-2024-45490" + }, + "fullDescription": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `XML_Parse()`\n- `XML_ParseBuffer()`\n\nAn additional condition, which the scanner currently does not check, is that the `len` parameter which is passed to those functions is user-controlled.", + "markdown": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `XML_Parse()`\n- `XML_ParseBuffer()`\n\nAn additional condition, which the scanner currently does not check, is that the `len` parameter which is passed to those functions is user-controlled." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-38428", + "name": "CVE-2024-38428", + "shortDescription": { + "text": "Scanner for CVE-2024-38428" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "undetermined", + "conclusion": "private" + } + }, + { + "id": "applic_CVE-2024-45492", + "name": "CVE-2024-45492", + "shortDescription": { + "text": "Scanner for CVE-2024-45492" + }, + "fullDescription": { + "text": "The scanner checks whether the current binary was compiled with 32-bit architecture and if any of the vulnerable functions are called:\n\n- `XML_ParseBuffer()`\n- `XML_Parse()`\n\nNote - the vulnerability occurs when certain inputs are passed to those functions.", + "markdown": "The scanner checks whether the current binary was compiled with 32-bit architecture and if any of the vulnerable functions are called:\n\n- `XML_ParseBuffer()`\n- `XML_Parse()`\n\nNote - the vulnerability occurs when certain inputs are passed to those functions." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2023-51767", + "name": "CVE-2023-51767", + "shortDescription": { + "text": "Scanner for CVE-2023-51767" + }, + "fullDescription": { + "text": "The CVE is always applicable.\n\nNote - The vulnerability is hardware-dependent.", + "markdown": "The CVE is always applicable.\n\nNote - The vulnerability is hardware-dependent." + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative" + } + }, + { + "id": "applic_CVE-2011-3374", + "name": "CVE-2011-3374", + "shortDescription": { + "text": "Scanner for CVE-2011-3374" + }, + "fullDescription": { + "text": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", + "markdown": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive", + "security-severity": "6.9" + } + }, + { + "id": "applic_CVE-2024-4741", + "name": "CVE-2024-4741", + "shortDescription": { + "text": "Scanner for CVE-2024-4741" + }, + "fullDescription": { + "text": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called.", + "markdown": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called." + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/user/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210780-681556384/Applicability_1726210780/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210535-1985298017/image.tar" + } + } + ], + "results": [ + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "applic_CVE-2024-4741", + "message": { + "text": "References to the vulnerable functions were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///usr/local/bin/node" + }, + "region": { + "snippet": { + "text": "" } } } - ] + } + ] + }, + { + "ruleId": "applic_CVE-2024-45490", + "kind": "pass", + "message": { + "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `XML_Parse()`\n- `XML_ParseBuffer()`\n\nAn additional condition, which the scanner currently does not check, is that the `len` parameter which is passed to those functions is user-controlled." + } + }, + { + "ruleId": "applic_CVE-2011-3374", + "kind": "pass", + "message": { + "text": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." + } + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" }, - { - "properties": { - "metadata": "", - "tokenValidation": "" - }, - "ruleId": "applic_CVE-2023-6246", - "message": { - "text": "The vulnerable function `vsyslog` is called in a suid/guid file" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "file:///usr/sbin/unix_chkpwd" - }, - "region": { - "snippet": { - "text": "" - } + "ruleId": "applic_CVE-2024-6119", + "message": { + "text": "References to the vulnerable functions were found" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///usr/local/bin/node" + }, + "region": { + "snippet": { + "text": "" } } } - ] - }, - { - "ruleId": "applic_CVE-2023-6879", - "kind": "pass", - "message": { - "text": "The scanner checks whether an encoding process is performed with the following requirements:\n\n* Using AV1 codec (`aom_codec_av1_cx()`).\n* Encoding (`aom_codec_encode()`)\n* Cleaning the memory at the end of the encoding process (`aom_codec_destroy()`).\n\nFor determining the applicability of this CVE, an additional condition (that the scanner currently does not check) should be verified: `aom` is configured to use more than 1 thread. For example:\n```\naom_codec_enc_cfg_t cfg;\naom_codec_enc_config_default(iface, \u0026cfg, AOM_USAGE_GOOD_QUALITY));\ncfg.g_threads = 4;\n```" - } - }, - { - "ruleId": "applic_CVE-2024-0553", - "kind": "pass", - "message": { - "text": "The scanner checks if RSA decryption occurs by finding calls to any of the following functions:\n\n- `gnutls_privkey_decrypt_data`\n\n- `gnutls_privkey_decrypt_data2`\n\nAn additional condition (that the scanner does not currently check) is required for the CVE to be applicable: the RSA padding algorithm needs to be `PKCS#1`. `key-\u003epk_algorithm` needs to be equal to `GNUTLS_PK_RSA`." } + ] + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" }, - { - "ruleId": "applic_CVE-2024-0567", - "kind": "pass", - "message": { - "text": "The scanner checks if any of the following vulnerable functions are called:\n\n- `gnutls_pcert_import_x509_list`\n\n- `gnutls_certificate_set_x509_key`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_mem`\n\n- `gnutls_certificate_set_x509_simple_pkcs12_file`\n\n- `gnutls_privkey_import_url`\n\n- `gnutls_privkey_import_pkcs11_url`\n\n- `gnutls_read_key_file`\n\n- `gnutls_certificate_set_rawpk_key_file`\n\n- `gnutls_certificate_set_x509_key_file2`\n\n- `gnutls_certificate_set_x509_key_file`\n\n- `gnutls_pcert_list_import_x509_file`\n\n- `gnutls_certificate_set_x509_key_mem2`\n\n- `gnutls_certificate_set_x509_key_mem`\n\n- `gnutls_x509_crt_list_import`\n\n- `gnutls_pcert_list_import_x509_raw`\n\n- `gnutls_session_channel_binding`\n\n- `gnutls_x509_crt_list_import2`\n\n- `gnutls_x509_trust_list_add_trust_mem`\n\n- `gnutls_x509_trust_list_add_system_trust`\n\n- `gnutls_certificate_set_x509_system_trust`\n\n- `gnutls_certificate_set_x509_crl_mem`\n\n- `gnutls_certificate_set_x509_trust_mem`\n\n- `gnutls_x509_trust_list_add_trust_file`\n\n- `gnutls_certificate_set_x509_crl_file`\n\n- `gnutls_certificate_set_x509_trust_file`\n\n- `gnutls_x509_trust_list_add_trust_dir`\n\n- `gnutls_certificate_set_x509_trust_dir`\n\n- `gnutls_x509_trust_list_remove_trust_mem`\n\n- `gnutls_x509_trust_list_remove_trust_file`\n\n- `gnutls_x509_trust_list_verify_crt2`\n\n- `gnutls_x509_cert_verify_peers`\n\n- `gnutls_certificate_verify_peers`\n\n- `gnutls_certificate_verify_peers2`\n\n- `gnutls_certificate_verify_peers3`\n\n- `gnutls_pkcs7_verify`\n\n- `gnutls_ocsp_resp_verify`\n\n- `gnutls_x509_trust_list_verify_crt`" - } + "ruleId": "applic_CVE-2024-6119", + "message": { + "text": "References to the vulnerable functions were found" }, - { - "ruleId": "applic_CVE-2024-25062", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the following functions are called:\n\n* `xmlValidatePopElement()`\n* `xmlTextReaderClose()`\n* `xmlFreeTextReader() `\n* `xmlTextReaderRead()`\n* `xmlSchemaValidateDoc()`" + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///usr/local/bin/node" + }, + "region": { + "snippet": { + "text": "" + } + } + } } + ] + }, + { + "ruleId": "applic_CVE-2024-45492", + "kind": "pass", + "message": { + "text": "The scanner checks whether the current binary was compiled with 32-bit architecture and if any of the vulnerable functions are called:\n\n- `XML_ParseBuffer()`\n- `XML_Parse()`\n\nNote - the vulnerability occurs when certain inputs are passed to those functions." + } + } + ] + } + ], + "secrets": [ + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Secrets scanner", + "rules": [ + { + "id": "REQ.SECRET.GENERIC.TEXT", + "name": "REQ.SECRET.GENERIC.TEXT", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.TEXT" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.GENERIC.CODE", + "name": "REQ.SECRET.GENERIC.CODE", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.CODE" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + }, + { + "id": "REQ.SECRET.KEYS", + "name": "REQ.SECRET.KEYS", + "shortDescription": { + "text": "Scanner for REQ.SECRET.KEYS" + }, + "fullDescription": { + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + }, + { + "id": "REQ.CRED.PUBLIC-ONLY", + "name": "REQ.CRED.PUBLIC-ONLY", + "shortDescription": { + "text": "Scanner for REQ.CRED.PUBLIC-ONLY" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "undetermined", + "conclusion": "private" + } + }, + { + "id": "REQ.SECRET.GENERIC.URL", + "name": "REQ.SECRET.GENERIC.URL", + "shortDescription": { + "text": "Scanner for REQ.SECRET.GENERIC.URL" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/user/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210780-681556384/Secrets_1726210839/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210535-1985298017/image.tar" + } + } + ], + "results": [ + { + "properties": { + "metadata": "", + "tokenValidation": "" }, - { - "ruleId": "applic_CVE-2024-2961", - "kind": "pass", - "message": { - "text": "" - } + "ruleId": "REQ.SECRET.GENERIC.CODE", + "message": { + "text": "Hardcoded secrets were found" }, - { - "ruleId": "applic_CVE-2024-33600", - "kind": "pass", - "message": { - "text": "The scanner checks whether the `nscd` binary exists on the machine." + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///private/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/tmpsfyn_3d1/unpacked/filesystem/blobs/sha256/9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0/usr/src/app/server/index.js" + }, + "region": { + "startLine": 5, + "startColumn": 7, + "endLine": 5, + "endColumn": 57, + "snippet": { + "text": "tok************" + } + } + } } + ] + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" }, - { - "ruleId": "applic_CVE-2024-33599", - "kind": "pass", - "message": { - "text": "The scanner checks whether the `nscd` binary exists on the machine." - } + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found" }, - { - "ruleId": "applic_CVE-2024-4741", - "kind": "pass", - "message": { - "text": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called." + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///private/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/tmpsfyn_3d1/unpacked/filesystem/blobs/sha256/9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0/usr/src/app/server/index.js" + }, + "region": { + "startLine": 6, + "startColumn": 14, + "endLine": 6, + "endColumn": 24, + "snippet": { + "text": "eyJ************" + } + } + } } + ] + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" }, - { - "ruleId": "applic_CVE-2023-49464", - "kind": "pass", - "message": { - "text": "The scanner checks for two conditions:\n\n1. The `libheif.so` binary was compiled with the vulnerable setting `-DWITH_UNCOMPRESSED_CODEC=ON`. \n\n2. Any of the following vulnerable functions are called:\n\n* `HeifContext::Image::get_luma_bits_per_pixel`\n* `HeifContext::decode_full_grid_image`\n* `HeifFile::get_luma_bits_per_pixel_from_configuration`\n* `UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci`\n* `heif_image_handle_get_luma_bits_per_pixel`" - } + "ruleId": "REQ.SECRET.GENERIC.URL", + "message": { + "text": "Hardcoded secrets were found" }, - { - "ruleId": "applic_CVE-2024-6119", - "kind": "pass", - "message": { - "text": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`" - } - } - ] - } - ], - "secrets": [ - { - "tool": { - "driver": { - "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", - "name": "JFrog Binary Secrets Scanner", - "rules": [ - { - "id": "REQ.SECRET.GENERIC.TEXT", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.TEXT" + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc" }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "help": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive" - } - }, - { - "id": "REQ.SECRET.GENERIC.CODE", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.CODE" - }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "help": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "undetermined", - "conclusion": "private" - } - }, - { - "id": "REQ.SECRET.KEYS", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.SECRET.KEYS" - }, - "fullDescription": { - "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", - "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" - }, - "help": { - "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", - "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" - }, - "properties": { - "applicability": "undetermined", - "conclusion": "private" - } - }, - { - "id": "REQ.CRED.PUBLIC-ONLY", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.CRED.PUBLIC-ONLY" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "help": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "undetermined", - "conclusion": "private" - } - }, - { - "id": "REQ.SECRET.GENERIC.URL", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.URL" - }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "help": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "undetermined", - "conclusion": "private" + "region": { + "snippet": { + "text": "htt************" + } } } - ], - "version": "1.0" - } - }, - "invocations": [ - { - "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", - "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1725978580-3584350251/Secrets_1725978603/config.yaml" - ], - "executionSuccessful": true, - "workingDirectory": { - "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1725978503-2625964325/image.tar" } - } - ], - "results": [] - } - ] - } + ] + } + ] + } + ] } - ] - } \ No newline at end of file + } + ] +} \ No newline at end of file diff --git a/tests/testdata/output/dockerscan/docker_sarif.json b/tests/testdata/output/dockerscan/docker_sarif.json index e69de29b..adda131f 100644 --- a/tests/testdata/output/dockerscan/docker_sarif.json +++ b/tests/testdata/output/dockerscan/docker_sarif.json @@ -0,0 +1,778 @@ +{ + "version": "2.1.0", + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "runs": [ + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Binary Secrets Scanner", + "rules": [ + { + "id": "REQ.SECRET.GENERIC.TEXT", + "name": "REQ.SECRET.GENERIC.TEXT", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.TEXT" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.GENERIC.CODE", + "name": "REQ.SECRET.GENERIC.CODE", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.CODE" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + }, + { + "id": "REQ.SECRET.KEYS", + "name": "REQ.SECRET.KEYS", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.KEYS" + }, + "fullDescription": { + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + "help": { + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + }, + { + "id": "REQ.CRED.PUBLIC-ONLY", + "name": "REQ.CRED.PUBLIC-ONLY", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.CRED.PUBLIC-ONLY" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "help": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "undetermined", + "conclusion": "private" + } + }, + { + "id": "REQ.SECRET.GENERIC.URL", + "name": "REQ.SECRET.GENERIC.URL", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.URL" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/user/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210780-681556384/Secrets_1726210839/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210535-1985298017/image.tar" + } + } + ], + "results": [ + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "REQ.SECRET.GENERIC.CODE", + "message": { + "text": "Hardcoded secrets were found", + "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: usr/src/app/server/index.js\nEvidence: tok************" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "usr/src/app/server/index.js" + }, + "region": { + "startLine": 5, + "startColumn": 7, + "endLine": 5, + "endColumn": 57, + "snippet": { + "text": "tok************" + } + } + }, + "logicalLocations": [ + { + "name": "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "00436fac1d19ea36302f14e892926efb" + } + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found", + "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: usr/src/app/server/index.js\nEvidence: eyJ************" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "usr/src/app/server/index.js" + }, + "region": { + "startLine": 6, + "startColumn": 14, + "endLine": 6, + "endColumn": 24, + "snippet": { + "text": "eyJ************" + } + } + }, + "logicalLocations": [ + { + "name": "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "2550dbdb124696ae8fcc5cfd6f2b65b8" + } + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "REQ.SECRET.GENERIC.URL", + "message": { + "text": "Hardcoded secrets were found", + "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nFilepath: usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc\nEvidence: htt************" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc" + }, + "region": { + "snippet": { + "text": "htt************" + } + } + } + } + ], + "fingerprints": { + "jfrogFingerprintHash": "9164423e88bbec9d1216bc5600eb7f9b" + } + } + ] + }, + { + "tool": { + "driver": { + "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sca", + "name": "JFrog Xray Scanner", + "rules": [ + { + "id": "CVE-2024-6119_debian:bookworm:openssl_3.0.13-1~deb12u1", + "shortDescription": { + "text": "[CVE-2024-6119] debian:bookworm:openssl 3.0.13-1~deb12u1" + }, + "help": { + "text": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | [3.0.14-1~deb12u2] |" + }, + "properties": { + "security-severity": "0.0" + } + }, + { + "id": "CVE-2024-38428_debian:bookworm:wget_1.21.3-1+b1", + "shortDescription": { + "text": "[CVE-2024-38428] debian:bookworm:wget 1.21.3-1+b1" + }, + "help": { + "text": "url.c in GNU Wget through 1.24.5 mishandles semicolons in the userinfo subcomponent of a URI, and thus there may be insecure behavior in which data that was supposed to be in the userinfo subcomponent is misinterpreted to be part of the host subcomponent.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.1 | Undetermined | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" + }, + "properties": { + "security-severity": "9.1" + } + }, + { + "id": "CVE-2024-45490_debian:bookworm:libexpat1_2.5.0-1", + "shortDescription": { + "text": "[CVE-2024-45490] debian:bookworm:libexpat1 2.5.0-1" + }, + "help": { + "text": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Not Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" + }, + "properties": { + "security-severity": "9.8" + } + }, + { + "id": "CVE-2024-45492_debian:bookworm:libexpat1_2.5.0-1", + "shortDescription": { + "text": "[CVE-2024-45492] debian:bookworm:libexpat1 2.5.0-1" + }, + "help": { + "text": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Not Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" + }, + "properties": { + "security-severity": "9.8" + } + }, + { + "id": "CVE-2024-4741_debian:bookworm:openssl_3.0.13-1~deb12u1", + "shortDescription": { + "text": "[CVE-2024-4741] debian:bookworm:openssl 3.0.13-1~deb12u1" + }, + "help": { + "text": "CVE-2024-4741", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | [3.0.14-1~deb12u1] |" + }, + "properties": { + "security-severity": "0.0" + } + }, + { + "id": "CVE-2024-6119_debian:bookworm:libssl3_3.0.13-1~deb12u1", + "shortDescription": { + "text": "[CVE-2024-6119] debian:bookworm:libssl3 3.0.13-1~deb12u1" + }, + "help": { + "text": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" + }, + "properties": { + "security-severity": "0.0" + } + }, + { + "id": "XRAY-264729_cors.js_0.0.1-security", + "shortDescription": { + "text": "[XRAY-264729] cors.js 0.0.1-security" + }, + "help": { + "text": "Malicious package cors.js for Node.js", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 10.0 | Not Covered | `sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar ` | No fix available |" + }, + "properties": { + "security-severity": "10.0" + } + }, + { + "id": "CVE-2023-51767_debian:bookworm:openssh-client:1_9.2p1-2+deb12u3", + "shortDescription": { + "text": "[CVE-2023-51767] debian:bookworm:openssh-client:1 9.2p1-2+deb12u3" + }, + "help": { + "text": "OpenSSH through 9.6, when common types of DRAM are used, might allow row hammer attacks (for authentication bypass) because the integer value of authenticated in mm_answer_authpassword does not resist flips of a single bit. NOTE: this is applicable to a certain threat model of attacker-victim co-location in which the attacker has user privileges.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.0 | Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" + }, + "properties": { + "security-severity": "7.0" + } + }, + { + "id": "CVE-2011-3374_debian:bookworm:apt_2.6.1", + "shortDescription": { + "text": "[CVE-2011-3374] debian:bookworm:apt 2.6.1" + }, + "help": { + "text": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.7 | Not Applicable | `sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ` | No fix available |" + }, + "properties": { + "security-severity": "3.7" + } + }, + { + "id": "CVE-2011-3374_debian:bookworm:libapt-pkg6.0_2.6.1", + "shortDescription": { + "text": "[CVE-2011-3374] debian:bookworm:libapt-pkg6.0 2.6.1" + }, + "help": { + "text": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.7 | Not Applicable | `sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ` | No fix available |" + }, + "properties": { + "security-severity": "3.7" + } + }, + { + "id": "CVE-2024-4741_debian:bookworm:libssl3_3.0.13-1~deb12u1", + "shortDescription": { + "text": "[CVE-2024-4741] debian:bookworm:libssl3 3.0.13-1~deb12u1" + }, + "help": { + "text": "CVE-2024-4741", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" + }, + "properties": { + "security-severity": "0.0" + } + } + ], + "version": "3.104.8" + } + }, + "invocations": [ + { + "executionSuccessful": true, + "workingDirectory": { + "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210535-1985298017/image.tar" + } + } + ], + "results": [ + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2024-6119_debian:bookworm:libssl3_3.0.13-1~deb12u1", + "ruleIndex": 5, + "level": "none", + "message": { + "text": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "5b5d2ba57a2eddf58f4579b7ebe42599" + } + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "[3.0.14-1~deb12u2]" + }, + "ruleId": "CVE-2024-6119_debian:bookworm:openssl_3.0.13-1~deb12u1", + "ruleIndex": 0, + "level": "none", + "message": { + "text": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "bd5908946de9c082f96e15217590eebc" + } + }, + { + "properties": { + "applicability": "Undetermined", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2024-38428_debian:bookworm:wget_1.21.3-1+b1", + "ruleIndex": 1, + "level": "error", + "message": { + "text": "[CVE-2024-38428] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-38428] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "db89861310f80a270a0a81f48d7dc974" + } + }, + { + "properties": { + "applicability": "Not Covered", + "fixedVersion": "No fix available" + }, + "ruleId": "XRAY-264729_cors.js_0.0.1-security", + "ruleIndex": 6, + "level": "error", + "message": { + "text": "[XRAY-264729] sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar ", + "markdown": "[XRAY-264729] sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" + } + }, + "logicalLocations": [ + { + "name": "ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "d653c414ef56560432b122358961104a" + } + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2024-45490_debian:bookworm:libexpat1_2.5.0-1", + "ruleIndex": 2, + "level": "error", + "message": { + "text": "[CVE-2024-45490] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", + "markdown": "[CVE-2024-45490] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + "logicalLocations": [ + { + "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "61be5170151428187e85ff7b27fd65b4" + } + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2024-45492_debian:bookworm:libexpat1_2.5.0-1", + "ruleIndex": 3, + "level": "error", + "message": { + "text": "[CVE-2024-45492] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", + "markdown": "[CVE-2024-45492] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + "logicalLocations": [ + { + "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "e47bb0a94451ed5111fabcf0ccaaeee6" + } + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2023-51767_debian:bookworm:openssh-client:1_9.2p1-2+deb12u3", + "ruleIndex": 7, + "level": "note", + "message": { + "text": "[CVE-2023-51767] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", + "markdown": "[CVE-2023-51767] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + "logicalLocations": [ + { + "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "fe7c1c90b3e7d340890027344468b42d" + } + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2011-3374_debian:bookworm:apt_2.6.1", + "ruleIndex": 8, + "level": "note", + "message": { + "text": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ", + "markdown": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + }, + "logicalLocations": [ + { + "name": "cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "81f98a6fd77d17d7647c0ae81410b506" + } + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2011-3374_debian:bookworm:libapt-pkg6.0_2.6.1", + "ruleIndex": 9, + "level": "note", + "message": { + "text": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ", + "markdown": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + }, + "logicalLocations": [ + { + "name": "cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "7933bf1c7b4635012e7571e82e619db6" + } + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2024-4741_debian:bookworm:libssl3_3.0.13-1~deb12u1", + "ruleIndex": 10, + "level": "none", + "message": { + "text": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "2c34553d9c75460bf14243ff13ba84c8" + } + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "[3.0.14-1~deb12u1]" + }, + "ruleId": "CVE-2024-4741_debian:bookworm:openssl_3.0.13-1~deb12u1", + "ruleIndex": 4, + "level": "none", + "message": { + "text": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "a374e04992f42ee827634927edd7e8d4" + } + } + ] + } + ] + } \ No newline at end of file diff --git a/tests/testdata/output/dockerscan/docker_simple_json.json b/tests/testdata/output/dockerscan/docker_simple_json.json index e69de29b..bb5a715a 100644 --- a/tests/testdata/output/dockerscan/docker_simple_json.json +++ b/tests/testdata/output/dockerscan/docker_simple_json.json @@ -0,0 +1,826 @@ +{ + "vulnerabilities": [ + { + "severity": "Critical", + "impactedPackageName": "debian:bookworm:wget", + "impactedPackageVersion": "1.21.3-1+b1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "url.c in GNU Wget through 1.24.5 mishandles semicolons in the userinfo subcomponent of a URI, and thus there may be insecure behavior in which data that was supposed to be in the userinfo subcomponent is misinterpreted to be part of the host subcomponent.", + "applicable": "Undetermined", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-38428", + "cvssV2": "", + "cvssV3": "9.1", + "applicability": { + "status": "Undetermined" + } + } + ], + "issueId": "XRAY-606103", + "references": [ + "https://git.savannah.gnu.org/cgit/wget.git/commit/?id=ed0c7c7e0e8f7298352646b2fd6e06a11e242ace", + "https://lists.gnu.org/archive/html/bug-wget/2024-06/msg00005.html", + "https://security-tracker.debian.org/tracker/CVE-2024-38428" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + { + "name": "debian:bookworm:wget", + "version": "1.21.3-1+b1", + "location": { + "file": "wget:1.21.3-1+b1" + } + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Critical", + "impactedPackageName": "cors.js", + "impactedPackageVersion": "0.0.1-security", + "impactedPackageType": "npm", + "components": [ + { + "name": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar", + "version": "", + "location": { + "file": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" + } + } + ], + "summary": "Malicious package cors.js for Node.js", + "applicable": "Not Covered", + "fixedVersions": null, + "cves": null, + "issueId": "XRAY-264729", + "references": [ + "https://registry.npmjs.com" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar", + "version": "", + "location": { + "file": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" + } + }, + { + "name": "cors.js", + "version": "0.0.1-security", + "location": { + "file": "usr/src/app/node_modules/cors.js/package.json" + } + } + ] + ], + "jfrogResearchInformation": { + "severity": "Critical", + "summary": "Malicious package cors.js for Node.js", + "details": "The package cors.js for Node.js contains malicious code that installs a persistent connectback shell. The package is typosquatting the popular `cors` package. When installed, the package opens a connectback shell to the hardcoded host `107.175.32.229` on TCP port 56173. The malicious payload achieves persistency by installing a cron job that repeats every 10 seconds - `*/10 * * * * *`", + "remediation": "As with any malware, the malicious package must be completely removed, and steps must be taken care to remediate the damage that was done by the malicious package -\n\n##### Removing the malicious package\n\nRun `npm uninstall cors.js`\n\n##### Refreshing stolen credentials\n\nMany malicious packages steal stored user credentials, focusing on the following -\n\n* [Browser autocomplete](https://jfrog.com/blog/malicious-pypi-packages-stealing-credit-cards-injecting-code/) data, such as saved passwords and credit cards\n* [Environment variables](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/) passed to the malicious code\n* [Stored Discord tokens](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)\n* AWS / GitHub credentials stored in cleartext files\n\nIt is highly recommended to change or revoke data that is stored in the infected machine at those locations\n\n##### Stopping malicious processes\n\nMany malicious packages start malicious processes such as [connectback shells](https://jfrog.com/blog/jfrog-discloses-3-remote-access-trojans-in-pypi/) or crypto-miners. Search for any unfamiliar processes that consume a large amount of CPU or a large amount of network traffic, and stop them. On Windows, this can be facilitated with [Sysinternals Process Explorer](https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer).\n\n##### Removing installed backdoors\n\nMany malicious packages install themselves as a [persistent backdoor](https://jfrog.com/blog/npm-supply-chain-attack-targets-german-based-companies/), in order to guarantee the malicious code survives a reboot. Search for any unfamiliar binaries set to be run on startup, and remove them. On Windows, this can be facilitated with [Sysinternals Autoruns](https://docs.microsoft.com/en-us/sysinternals/downloads/autoruns).\n\n##### Defining an Xray policy that blocks downloads of Artifacts with malicious packages\n\nIt is possible to [create an Xray policy](https://www.jfrog.com/confluence/display/JFROG/Creating+Xray+Policies+and+Rules) that will not allow artifacts with identified malicious packages to be downloaded from Artifactory. To create such a policy, add a new `Security` policy and set `Minimal Severity` to `Critical`. Under `Automatic Actions` check the `Block Download` action.\n\n##### Contacting the JFrog Security Research team for additional information\n\nOptionally, if you are unsure of the full impact of the malicious package and wish to get more details, the JFrog Security Research team can help you assess the potential damage from the installed malicious package.\n\nPlease contact us at research@jfrog.com with details of the affected artifact and the name of the identified malicious package." + } + }, + { + "severity": "Low", + "impactedPackageName": "debian:bookworm:openssh-client:1", + "impactedPackageVersion": "9.2p1-2+deb12u3", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + } + ], + "summary": "OpenSSH through 9.6, when common types of DRAM are used, might allow row hammer attacks (for authentication bypass) because the integer value of authenticated in mm_answer_authpassword does not resist flips of a single bit. NOTE: this is applicable to a certain threat model of attacker-victim co-location in which the attacker has user privileges.", + "applicable": "Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2023-51767", + "cvssV2": "", + "cvssV3": "7.0", + "applicability": { + "status": "Applicable", + "scannerDescription": "The CVE is always applicable.\n\nNote - The vulnerability is hardware-dependent." + } + } + ], + "issueId": "XRAY-585612", + "references": [ + "https://arxiv.org/abs/2309.02545", + "https://github.com/openssh/openssh-portable/blob/8241b9c0529228b4b86d88b1a6076fb9f97e4a99/monitor.c#L878", + "https://github.com/openssh/openssh-portable/blob/8241b9c0529228b4b86d88b1a6076fb9f97e4a99/auth-passwd.c#L77", + "https://bugzilla.redhat.com/show_bug.cgi?id=2255850", + "https://security-tracker.debian.org/tracker/CVE-2023-51767", + "https://ubuntu.com/security/CVE-2023-51767", + "https://security.netapp.com/advisory/ntap-20240125-0006/", + "https://access.redhat.com/security/cve/CVE-2023-51767" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + { + "name": "debian:bookworm:openssh-client:1", + "version": "9.2p1-2+deb12u3", + "location": { + "file": "openssh-client:1:9.2p1-2+deb12u3" + } + } + ] + ], + "jfrogResearchInformation": { + "severity": "Low", + "summary": "The RowHammer fault injection attack can theoretically lead to local authentication bypass in OpenSSH.", + "details": "[OpenSSH](https://www.openssh.com/) is a popular open-source implementation of the SSH (Secure Shell) protocol, providing encrypted communication over a network.\nIt was discovered that the OpenSSH authentication logic can be susceptible in some cases to a side-channel fault injection attack. The attack can theoretically be carried out by a local attacker which eventually bypass OpenSSH authentication mechanism.\n\nThis vulnerability currently lacks widely known published exploits, and its exploitation is considered highly complex. The intricacies of the attack, combined with the absence of well-documented exploits, contribute to the difficulty in achieving successful exploitation. Furthermore, it's essential to note that the susceptibility to this vulnerability is hardware-dependent, and the success of an attack relies on probabilities associated with the specific hardware configuration. \n\nThe vulnerability is theoretically exploitable by several different ways, the only two published ways are:\n\nIn the OpenSSH function `mm_answer_authpassword()`, a stack variable `authenticated`, is assigned to the value of the function `auth_password()` which returns 1/0 and then returned. If the value of `authenticated` is 1, the SSH connection will be established. Since `authenticated` is stored on the stack, therefore in DRAM, a local attacker could flip this 32-bit integer least significant bit, thus, bypass authentication.\n\nAnother possible exploit is the `result` stack variable in `auth_password()` function. It is initialized to 0 and set to 1 if the password is correct. \nSimilarly to the previous method, this attack requires a single bit flip of the `result` variable in order for the function to return 1 and bypass the authentication.\n\nAttackers can trigger the vulnerability via a RowHammer fault injection. The Rowhammer bug is a hardware reliability issue in which an attacker repeatedly accesses (hammers) DRAM cells to cause unauthorized changes in physically adjacent memory locations.\nSimply put:\n\n* A specific register value(`authenticated`/`result` value) is pushed onto the stack during program execution. \n* The stack, where the register value is stored, is identified to be located in a memory row susceptible to bit flips (flippable row) due to the RowHammer vulnerability in DRAM.\n* The attacker performs a series of rapid and repeated memory accesses to the adjacent rows of the flippable row in the DRAM. This repeated access exploits the RowHammer vulnerability, inducing bit flips in the targeted flippable row.\n* Due to the RowHammer effect, bit flips occur in the flippable row, potentially corrupting the data stored there.\n* After inducing bit flips in the flippable row, the attacker manipulates the program's control flow to pop the corrupted value from the stack into a register.\n* The register now holds a value that has been corrupted through the RowHammer attack. Now the `authenticated`/`result` variables hold this corrupted value thus it can lead to authentication bypass, as it may impact the control flow in a way advantageous to the attacker.", + "severityReasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The vulnerability depends on the OS and hardware. It was only evaluated in one test environment, therefore results for other conditions might differ. The attacker must be extremely familiar with the details of the exploited system (ex. know the exact hardware which is running the OS).", + "isPositive": true + }, + { + "name": "The issue can only be exploited by an attacker that can execute code on the vulnerable machine (excluding exceedingly rare circumstances)", + "isPositive": true + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Exploitation is extremely non-trivial (even theoretically), no public exploits have been published.", + "isPositive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The vulnerability's attack complexity is significantly higher than what the CVSS represents.", + "isPositive": true + } + ] + } + }, + { + "severity": "Unknown", + "impactedPackageName": "debian:bookworm:libssl3", + "impactedPackageVersion": "3.0.13-1~deb12u1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "CVE-2024-4741", + "applicable": "Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-4741", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called.", + "evidence": [ + { + "file": "usr/local/bin/node", + "reason": "References to the vulnerable functions were found" + } + ] + } + } + ], + "issueId": "XRAY-603657", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-4741" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + { + "name": "debian:bookworm:libssl3", + "version": "3.0.13-1~deb12u1", + "location": { + "file": "libssl3:3.0.13-1~deb12u1" + } + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Unknown", + "impactedPackageName": "debian:bookworm:openssl", + "impactedPackageVersion": "3.0.13-1~deb12u1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "CVE-2024-4741", + "applicable": "Applicable", + "fixedVersions": [ + "[3.0.14-1~deb12u1]" + ], + "cves": [ + { + "id": "CVE-2024-4741", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called.", + "evidence": [ + { + "file": "usr/local/bin/node", + "reason": "References to the vulnerable functions were found" + } + ] + } + } + ], + "issueId": "XRAY-603657", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-4741" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + { + "name": "debian:bookworm:openssl", + "version": "3.0.13-1~deb12u1", + "location": { + "file": "openssl:3.0.13-1~deb12u1" + } + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Unknown", + "impactedPackageName": "debian:bookworm:libssl3", + "impactedPackageVersion": "3.0.13-1~deb12u1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", + "applicable": "Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-6119", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`", + "evidence": [ + { + "file": "usr/local/bin/node", + "reason": "References to the vulnerable functions were found" + } + ] + } + } + ], + "issueId": "XRAY-632747", + "references": [ + "https://openssl-library.org/news/secadv/20240903.txt", + "https://github.com/openssl/openssl/commit/621f3729831b05ee828a3203eddb621d014ff2b2", + "https://github.com/openssl/openssl/commit/05f360d9e849a1b277db628f1f13083a7f8dd04f", + "https://security-tracker.debian.org/tracker/CVE-2024-6119", + "https://github.com/openssl/openssl/commit/7dfcee2cd2a63b2c64b9b4b0850be64cb695b0a0", + "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + { + "name": "debian:bookworm:libssl3", + "version": "3.0.13-1~deb12u1", + "location": { + "file": "libssl3:3.0.13-1~deb12u1" + } + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Out of bounds read in OpenSSL clients can lead to denial of service when using non-default TLS verification options and connecting to malicious TLS servers", + "severityReasons": [ + { + "name": "The issue has an exploit published", + "description": "The fix commit contains PoC certificates that trigger the denial of service issue" + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker must make the victim client connect to their malicious TLS server, in order to serve the malformed TLS certificate. The victim client must use OpenSSL and must enable non-default certificate verification options, either -\n\n* DNS verification - by using `X509_VERIFY_PARAM_set1_host` or `X509_check_host`\n* Email verification - by using ` X509_VERIFY_PARAM_set1_email` or `X509_check_email`", + "isPositive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Denial of service of a TLS clients only. This out of bounds read cannot lead to data disclosure.", + "isPositive": true + } + ] + } + }, + { + "severity": "Unknown", + "impactedPackageName": "debian:bookworm:openssl", + "impactedPackageVersion": "3.0.13-1~deb12u1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", + "applicable": "Applicable", + "fixedVersions": [ + "[3.0.14-1~deb12u2]" + ], + "cves": [ + { + "id": "CVE-2024-6119", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`", + "evidence": [ + { + "file": "usr/local/bin/node", + "reason": "References to the vulnerable functions were found" + } + ] + } + } + ], + "issueId": "XRAY-632747", + "references": [ + "https://openssl-library.org/news/secadv/20240903.txt", + "https://github.com/openssl/openssl/commit/621f3729831b05ee828a3203eddb621d014ff2b2", + "https://github.com/openssl/openssl/commit/05f360d9e849a1b277db628f1f13083a7f8dd04f", + "https://security-tracker.debian.org/tracker/CVE-2024-6119", + "https://github.com/openssl/openssl/commit/7dfcee2cd2a63b2c64b9b4b0850be64cb695b0a0", + "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + { + "name": "debian:bookworm:openssl", + "version": "3.0.13-1~deb12u1", + "location": { + "file": "openssl:3.0.13-1~deb12u1" + } + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Out of bounds read in OpenSSL clients can lead to denial of service when using non-default TLS verification options and connecting to malicious TLS servers", + "severityReasons": [ + { + "name": "The issue has an exploit published", + "description": "The fix commit contains PoC certificates that trigger the denial of service issue" + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker must make the victim client connect to their malicious TLS server, in order to serve the malformed TLS certificate. The victim client must use OpenSSL and must enable non-default certificate verification options, either -\n\n* DNS verification - by using `X509_VERIFY_PARAM_set1_host` or `X509_check_host`\n* Email verification - by using ` X509_VERIFY_PARAM_set1_email` or `X509_check_email`", + "isPositive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Denial of service of a TLS clients only. This out of bounds read cannot lead to data disclosure.", + "isPositive": true + } + ] + } + }, + { + "severity": "Critical", + "impactedPackageName": "debian:bookworm:libexpat1", + "impactedPackageVersion": "2.5.0-1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + } + ], + "summary": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", + "applicable": "Not Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-45490", + "cvssV2": "", + "cvssV3": "9.8", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `XML_Parse()`\n- `XML_ParseBuffer()`\n\nAn additional condition, which the scanner currently does not check, is that the `len` parameter which is passed to those functions is user-controlled." + } + } + ], + "issueId": "XRAY-632613", + "references": [ + "https://github.com/libexpat/libexpat/issues/887", + "https://security-tracker.debian.org/tracker/CVE-2024-45490", + "https://github.com/libexpat/libexpat/pull/890" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + { + "name": "debian:bookworm:libexpat1", + "version": "2.5.0-1", + "location": { + "file": "libexpat1:2.5.0-1" + } + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Critical", + "impactedPackageName": "debian:bookworm:libexpat1", + "impactedPackageVersion": "2.5.0-1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + } + ], + "summary": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", + "applicable": "Not Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-45492", + "cvssV2": "", + "cvssV3": "9.8", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the current binary was compiled with 32-bit architecture and if any of the vulnerable functions are called:\n\n- `XML_ParseBuffer()`\n- `XML_Parse()`\n\nNote - the vulnerability occurs when certain inputs are passed to those functions." + } + } + ], + "issueId": "XRAY-632612", + "references": [ + "https://github.com/libexpat/libexpat/issues/889", + "https://security-tracker.debian.org/tracker/CVE-2024-45492", + "https://github.com/libexpat/libexpat/pull/892" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + { + "name": "debian:bookworm:libexpat1", + "version": "2.5.0-1", + "location": { + "file": "libexpat1:2.5.0-1" + } + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Low", + "impactedPackageName": "debian:bookworm:libapt-pkg6.0", + "impactedPackageVersion": "2.6.1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", + "version": "", + "location": { + "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + } + ], + "summary": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", + "applicable": "Not Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2011-3374", + "cvssV2": "4.3", + "cvssV3": "3.7", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." + } + } + ], + "issueId": "XRAY-34417", + "references": [ + "https://people.canonical.com/~ubuntu-security/cve/2011/CVE-2011-3374.html", + "https://seclists.org/fulldisclosure/2011/Sep/221", + "https://ubuntu.com/security/CVE-2011-3374", + "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=642480", + "https://access.redhat.com/security/cve/cve-2011-3374", + "https://snyk.io/vuln/SNYK-LINUX-APT-116518", + "https://security-tracker.debian.org/tracker/CVE-2011-3374" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", + "version": "", + "location": { + "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + }, + { + "name": "debian:bookworm:libapt-pkg6.0", + "version": "2.6.1", + "location": { + "file": "libapt-pkg6.0:2.6.1" + } + } + ] + ], + "jfrogResearchInformation": { + "severity": "High", + "summary": "Improper signature validation in apt-key may enable Man-in-the-Middle attacks and result in code execution.", + "details": "`apt-key` is [`apt`](https://github.com/Debian/apt)'s key management utility, and is used to manage the keys that are used by `apt` to authenticate packages.\n\nA vulnerability in `apt-key`'s `net-update` function exists, in which [`GPG`](https://www.gnupg.org/) keys, that are used for signing packages and validating their authenticity, aren't validated correctly. The `net-update` function pulls the signing keys that should be added from an insecure location (`http://...`), exposing it to a Man-in-the-Middle attack in which malicious signing keys could be added to the system's keyring. This issue happens due to a vulnerability in the `add_keys_with_veirfy_against_master_keyring()` function, which allows adding signing keys without proper signature validation. \n\nThis vulnerability then potentially allows a malicious actor to perform a Man-in-the-Middle attack on a target, by making it validate malicious packages that were signed with the `GPG` signing key used by the attacker. Effectively, this means that `apt` can be duped to install malicious services and daemons with root privileges.\n\nThe conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man In The Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from [python-apt](https://pypi.org/project/python-apt/) Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.\n\nDo note that `apt-key` is **deprecated** and shouldn't be used, and in most Debian versions `ARCHIVE_KEYRING_URI` is not defined, making this vulnerability unexploitable in most Debian systems.", + "severityReasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the python-apt Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", + "isPositive": true + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "This vulnerability is remotely exploitable when the applicability conditions apply." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Remote code execution is possible when the applicability conditions apply." + }, + { + "name": "The issue has an exploit published", + "description": "The reporter of this issue has provided a GPG key that can be used for an actual attack, as well as a simple PoC example." + } + ], + "remediation": "##### Deployment mitigations\n\n* Dot not execute `apt-key` command, as it is deprecated.\n* Remove the URI configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`." + } + }, + { + "severity": "Low", + "impactedPackageName": "debian:bookworm:apt", + "impactedPackageVersion": "2.6.1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", + "version": "", + "location": { + "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + } + ], + "summary": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", + "applicable": "Not Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2011-3374", + "cvssV2": "4.3", + "cvssV3": "3.7", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." + } + } + ], + "issueId": "XRAY-34417", + "references": [ + "https://people.canonical.com/~ubuntu-security/cve/2011/CVE-2011-3374.html", + "https://seclists.org/fulldisclosure/2011/Sep/221", + "https://ubuntu.com/security/CVE-2011-3374", + "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=642480", + "https://access.redhat.com/security/cve/cve-2011-3374", + "https://snyk.io/vuln/SNYK-LINUX-APT-116518", + "https://security-tracker.debian.org/tracker/CVE-2011-3374" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", + "version": "", + "location": { + "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + }, + { + "name": "debian:bookworm:apt", + "version": "2.6.1", + "location": { + "file": "apt:2.6.1" + } + } + ] + ], + "jfrogResearchInformation": { + "severity": "High", + "summary": "Improper signature validation in apt-key may enable Man-in-the-Middle attacks and result in code execution.", + "details": "`apt-key` is [`apt`](https://github.com/Debian/apt)'s key management utility, and is used to manage the keys that are used by `apt` to authenticate packages.\n\nA vulnerability in `apt-key`'s `net-update` function exists, in which [`GPG`](https://www.gnupg.org/) keys, that are used for signing packages and validating their authenticity, aren't validated correctly. The `net-update` function pulls the signing keys that should be added from an insecure location (`http://...`), exposing it to a Man-in-the-Middle attack in which malicious signing keys could be added to the system's keyring. This issue happens due to a vulnerability in the `add_keys_with_veirfy_against_master_keyring()` function, which allows adding signing keys without proper signature validation. \n\nThis vulnerability then potentially allows a malicious actor to perform a Man-in-the-Middle attack on a target, by making it validate malicious packages that were signed with the `GPG` signing key used by the attacker. Effectively, this means that `apt` can be duped to install malicious services and daemons with root privileges.\n\nThe conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man In The Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from [python-apt](https://pypi.org/project/python-apt/) Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.\n\nDo note that `apt-key` is **deprecated** and shouldn't be used, and in most Debian versions `ARCHIVE_KEYRING_URI` is not defined, making this vulnerability unexploitable in most Debian systems.", + "severityReasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the python-apt Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", + "isPositive": true + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "This vulnerability is remotely exploitable when the applicability conditions apply." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Remote code execution is possible when the applicability conditions apply." + }, + { + "name": "The issue has an exploit published", + "description": "The reporter of this issue has provided a GPG key that can be used for an actual attack, as well as a simple PoC example." + } + ], + "remediation": "##### Deployment mitigations\n\n* Dot not execute `apt-key` command, as it is deprecated.\n* Remove the URI configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`." + } + } + ], + "securityViolations": null, + "licensesViolations": null, + "licenses": null, + "operationalRiskViolations": null, + "secrets": [ + { + "severity": "Medium", + "file": "usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc", + "snippet": "htt************", + "finding": "Hardcoded secrets were found", + "scannerDescription": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + { + "severity": "Medium", + "file": "private/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/tmpsfyn_3d1/unpacked/filesystem/blobs/sha256/9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0/usr/src/app/server/index.js", + "startLine": 5, + "startColumn": 7, + "endLine": 5, + "endColumn": 57, + "snippet": "tok************", + "finding": "Hardcoded secrets were found", + "scannerDescription": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + { + "severity": "Medium", + "file": "private/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/tmpsfyn_3d1/unpacked/filesystem/blobs/sha256/9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0/usr/src/app/server/index.js", + "startLine": 6, + "startColumn": 14, + "endLine": 6, + "endColumn": 24, + "snippet": "eyJ************", + "finding": "Secret keys were found", + "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + } + ], + "iacViolations": null, + "sastViolations": null, + "errors": null + } \ No newline at end of file diff --git a/tests/testdata/output/dockerscan/docker_summary.json b/tests/testdata/output/dockerscan/docker_summary.json index 8fa8d1ed..f325e059 100644 --- a/tests/testdata/output/dockerscan/docker_summary.json +++ b/tests/testdata/output/dockerscan/docker_summary.json @@ -1,77 +1,43 @@ { - "resultType": "docker_image", - "args": { - "base_jfrog_url": "https://tokyoshiftleft.jfrog.io/", - "docker_image": "nginx:latest" - }, - "summary": { - "scans": [ - { - "target": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1725978503-2625964325/image.tar", - "name": "nginx:latest", - "vulnerabilities": { - "sca": { - "scan_ids": [ - "f1ca2a08-1d7b-4194-72be-7b84afc51fac" - ], - "security": { - "Critical": { - "Not Applicable": 4, - "Not Covered": 3 - }, - "High": { - "Applicable": 1, - "Not Applicable": 19, - "Not Covered": 5, - "Undetermined": 2 - }, - "Low": { - "Not Applicable": 5, - "Not Covered": 47 - }, - "Medium": { - "Not Applicable": 3, - "Not Covered": 28 - }, - "Unknown": { - "Applicable": 1, - "Not Applicable": 5, - "Not Covered": 21, - "Undetermined": 1 - } - } - }, - "iac": {}, - "secrets": {}, - "sast": {} - }, - "violations": { - "watches": [ - "Security_watch_1" - ], - "sca": { - "scan_ids": [ - "f1ca2a08-1d7b-4194-72be-7b84afc51fac" - ], - "security": { - "Critical": { - "Not Applicable": 4, - "Not Covered": 3 - }, - "High": { - "Applicable": 1, - "Not Applicable": 19, - "Not Covered": 5, - "Undetermined": 2 - }, - "Medium": { - "Not Applicable": 3, - "Not Covered": 28 - } - } - } - } + "scans": [ + { + "target": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210535-1985298017/image.tar", + "name": "platform.jfrog.io/swamp-docker/swamp:latest", + "vulnerabilities": { + "sca": { + "scan_ids": [ + "27da9106-88ea-416b-799b-bc7d15783473" + ], + "security": { + "Critical": { + "Not Applicable": 2, + "Not Covered": 1, + "Undetermined": 1 + }, + "Low": { + "Applicable": 1, + "Not Applicable": 1 + }, + "Unknown": { + "Applicable": 2 + } } - ] - } -} \ No newline at end of file + }, + "iac": {}, + "secrets": { + "Medium": { + "": 3 + } + }, + "sast": {} + }, + "violations": { + "sca": { + "scan_ids": [ + "27da9106-88ea-416b-799b-bc7d15783473" + ] + } + } + } + ] + } \ No newline at end of file diff --git a/tests/testdata/projects/jas/jas-config/sast/result.sarif b/tests/testdata/projects/jas/jas-config/sast/result.sarif index 839f3481..c499a4aa 100644 --- a/tests/testdata/projects/jas/jas-config/sast/result.sarif +++ b/tests/testdata/projects/jas/jas-config/sast/result.sarif @@ -63,12 +63,12 @@ { "executionSuccessful": true, "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", + "/users/user/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", "scan", "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1693492973-1963413933/results.sarif" ], "workingDirectory": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast" + "uri": "file:///Users/user/testdata/xray/jas/sast" } } ], @@ -87,7 +87,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/__init__.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/__init__.py" }, "region": { "endColumn": 39, @@ -117,7 +117,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/__init__.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/__init__.py" }, "region": { "endColumn": 39, @@ -151,7 +151,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 31, @@ -174,7 +174,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 35, @@ -197,7 +197,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 44, @@ -220,7 +220,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 16, @@ -243,7 +243,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 10, @@ -266,7 +266,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 10, @@ -295,7 +295,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 10, @@ -329,7 +329,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 31, @@ -352,7 +352,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 35, @@ -375,7 +375,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 44, @@ -398,7 +398,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 16, @@ -421,7 +421,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 63, @@ -444,7 +444,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 70, @@ -467,7 +467,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 76, @@ -490,7 +490,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 16, @@ -513,7 +513,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 62, @@ -536,7 +536,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 62, @@ -565,7 +565,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 62, @@ -594,7 +594,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/run.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/run.py" }, "region": { "endColumn": 24, diff --git a/tests/testdata/projects/jas/jas/sast/result.sarif b/tests/testdata/projects/jas/jas/sast/result.sarif index 839f3481..c499a4aa 100644 --- a/tests/testdata/projects/jas/jas/sast/result.sarif +++ b/tests/testdata/projects/jas/jas/sast/result.sarif @@ -63,12 +63,12 @@ { "executionSuccessful": true, "arguments": [ - "/Users/assafa/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", + "/users/user/.jfrog/dependencies/analyzerManager/zd_scanner/scanner", "scan", "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1693492973-1963413933/results.sarif" ], "workingDirectory": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast" + "uri": "file:///Users/user/testdata/xray/jas/sast" } } ], @@ -87,7 +87,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/__init__.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/__init__.py" }, "region": { "endColumn": 39, @@ -117,7 +117,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/__init__.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/__init__.py" }, "region": { "endColumn": 39, @@ -151,7 +151,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 31, @@ -174,7 +174,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 35, @@ -197,7 +197,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 44, @@ -220,7 +220,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 16, @@ -243,7 +243,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 10, @@ -266,7 +266,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 10, @@ -295,7 +295,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 10, @@ -329,7 +329,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 31, @@ -352,7 +352,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 35, @@ -375,7 +375,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 44, @@ -398,7 +398,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 16, @@ -421,7 +421,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 63, @@ -444,7 +444,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 70, @@ -467,7 +467,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 76, @@ -490,7 +490,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 16, @@ -513,7 +513,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 62, @@ -536,7 +536,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 62, @@ -565,7 +565,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/flask_webgoat/ui.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/flask_webgoat/ui.py" }, "region": { "endColumn": 62, @@ -594,7 +594,7 @@ ], "physicalLocation": { "artifactLocation": { - "uri": "file:///Users/assafa/Documents/code/cli-projects/jfrog-cli/testdata/xray/jas/sast/run.py" + "uri": "file:///Users/user/testdata/xray/jas/sast/run.py" }, "region": { "endColumn": 24, diff --git a/utils/formats/sarifutils/sarifutils.go b/utils/formats/sarifutils/sarifutils.go index 6bc9144d..833f05e6 100644 --- a/utils/formats/sarifutils/sarifutils.go +++ b/utils/formats/sarifutils/sarifutils.go @@ -29,6 +29,68 @@ func CombineReports(reports ...*sarif.Report) (combined *sarif.Report, err error return } +func GetToolVersion(run *sarif.Run) string { + if run.Tool.Driver != nil && run.Tool.Driver.Version != nil { + return *run.Tool.Driver.Version + } + return "" +} + +func CopyRunMetadata(run *sarif.Run) (copied *sarif.Run) { + if run == nil { + return + } + copied = sarif.NewRun(*sarif.NewTool(sarif.NewDriver(GetRunToolName(run)))).WithInvocations(run.Invocations) + + if toolFullName := GetRunToolFullName(run); toolFullName != "" { + copied.Tool.Driver.FullName = &toolFullName + } + if toolVersion := GetToolVersion(run); toolVersion != "" { + copied.Tool.Driver.Version = &toolVersion + } + if fullDescription := GetRunToolFullDescription(run); fullDescription != "" { + SetRunToolFullDescriptionText(fullDescription, copied) + } + if fullDescriptionMarkdown := GetRunToolFullDescriptionMarkdown(run); fullDescriptionMarkdown != "" { + SetRunToolFullDescriptionMarkdown(fullDescriptionMarkdown, copied) + } + if language := getRunLanguage(run); language != "" { + copied.Language = &language + } + if informationURI := GetRunToolInformationURI(run); informationURI != "" { + copied.Tool.Driver.InformationURI = &informationURI + } + return +} + +func GetRunToolFullName(run *sarif.Run) string { + if run.Tool.Driver != nil && run.Tool.Driver.FullName != nil { + return *run.Tool.Driver.FullName + } + return "" +} + +func GetRunToolFullDescription(run *sarif.Run) string { + if run.Tool.Driver != nil && run.Tool.Driver.FullDescription != nil && run.Tool.Driver.FullDescription.Text != nil { + return *run.Tool.Driver.FullDescription.Text + } + return "" +} + +func getRunLanguage(run *sarif.Run) string { + if run.Language != nil { + return *run.Language + } + return "" +} + +func GetRunToolInformationURI(run *sarif.Run) string { + if run.Tool.Driver != nil && run.Tool.Driver.InformationURI != nil { + return *run.Tool.Driver.InformationURI + } + return "" +} + func NewPhysicalLocation(physicalPath string) *sarif.PhysicalLocation { return &sarif.PhysicalLocation{ ArtifactLocation: &sarif.ArtifactLocation{ @@ -67,14 +129,14 @@ func ReadScanRunsFromFile(fileName string) (sarifRuns []*sarif.Run, err error) { func CopyResult(result *sarif.Result) *sarif.Result { copied := &sarif.Result{ - RuleID: result.RuleID, - RuleIndex: result.RuleIndex, - Kind: result.Kind, + RuleID: result.RuleID, + RuleIndex: result.RuleIndex, + Kind: result.Kind, Fingerprints: result.Fingerprints, CodeFlows: result.CodeFlows, - Level: result.Level, - Message: result.Message, - PropertyBag: result.PropertyBag, + Level: result.Level, + Message: result.Message, + PropertyBag: result.PropertyBag, } for _, location := range result.Locations { copied.Locations = append(copied.Locations, CopyLocation(location)) @@ -82,29 +144,56 @@ func CopyResult(result *sarif.Result) *sarif.Result { return copied } +func copyStrAttribute(attr *string) *string { + if attr == nil { + return nil + } + copy := *attr + return © +} + +func copyIntAttribute(attr *int) *int { + if attr == nil { + return nil + } + copy := *attr + return © +} + func CopyLocation(location *sarif.Location) *sarif.Location { - copied := &sarif.Location{ - PhysicalLocation: &sarif.PhysicalLocation{ - ArtifactLocation: &sarif.ArtifactLocation{ - URI: location.PhysicalLocation.ArtifactLocation.URI, - }, - Region: &sarif.Region{ - StartLine: location.PhysicalLocation.Region.StartLine, - StartColumn: location.PhysicalLocation.Region.StartColumn, - EndLine: location.PhysicalLocation.Region.EndLine, - EndColumn: location.PhysicalLocation.Region.EndColumn, - Snippet: location.PhysicalLocation.Region.Snippet, - }, - }, + if location == nil { + return nil + } + copied := sarif.NewLocation() + if location.PhysicalLocation != nil { + copied.PhysicalLocation = &sarif.PhysicalLocation{} + if location.PhysicalLocation.ArtifactLocation != nil { + copied.PhysicalLocation.ArtifactLocation = &sarif.ArtifactLocation{ + URI: copyStrAttribute(location.PhysicalLocation.ArtifactLocation.URI), + } + } + if location.PhysicalLocation.Region != nil { + copied.PhysicalLocation.Region = &sarif.Region{ + StartLine: copyIntAttribute(location.PhysicalLocation.Region.StartLine), + StartColumn: copyIntAttribute(location.PhysicalLocation.Region.StartColumn), + EndLine: copyIntAttribute(location.PhysicalLocation.Region.EndLine), + EndColumn: copyIntAttribute(location.PhysicalLocation.Region.EndColumn), + } + if location.PhysicalLocation.Region.Snippet != nil { + copied.PhysicalLocation.Region.Snippet = &sarif.ArtifactContent{ + Text: copyStrAttribute(location.PhysicalLocation.Region.Snippet.Text), + } + } + } } copied.Properties = location.Properties for _, logicalLocation := range location.LogicalLocations { copied.LogicalLocations = append(copied.LogicalLocations, &sarif.LogicalLocation{ - Name: logicalLocation.Name, + Name: logicalLocation.Name, FullyQualifiedName: logicalLocation.FullyQualifiedName, - DecoratedName: logicalLocation.DecoratedName, - Kind: logicalLocation.Kind, - PropertyBag: logicalLocation.PropertyBag, + DecoratedName: logicalLocation.DecoratedName, + Kind: logicalLocation.Kind, + PropertyBag: logicalLocation.PropertyBag, }) } return copied @@ -168,7 +257,7 @@ func GetLogicalLocation(kind string, location *sarif.Location) *sarif.LogicalLoc func GetLocationId(location *sarif.Location) string { return fmt.Sprintf("%s:%s:%d:%d:%d:%d", GetLocationFileName(location), - GetLocationSnippet(location), + GetLocationSnippetText(location), GetLocationStartLine(location), GetLocationStartColumn(location), GetLocationEndLine(location), @@ -183,6 +272,13 @@ func SetRunToolName(toolName string, run *sarif.Run) { run.Tool.Driver.Name = toolName } +func GetRunToolName(run *sarif.Run) string { + if run.Tool.Driver != nil { + return run.Tool.Driver.Name + } + return "" +} + func SetRunToolFullDescriptionText(txt string, run *sarif.Run) { if run.Tool.Driver == nil { run.Tool.Driver = &sarif.ToolComponent{} @@ -218,13 +314,6 @@ func GetRunToolFullDescriptionMarkdown(run *sarif.Run) string { return "" } -func GetRunToolName(run *sarif.Run) string { - if run.Tool.Driver != nil { - return run.Tool.Driver.Name - } - return "" -} - func GetResultsLocationCount(runs ...*sarif.Run) (count int) { for _, run := range runs { for _, result := range run.Results { @@ -307,19 +396,27 @@ func SetResultFingerprint(algorithm, value string, result *sarif.Result) { func GetResultLocationSnippets(result *sarif.Result) []string { var snippets []string for _, location := range result.Locations { - if snippet := GetLocationSnippet(location); snippet != "" { + if snippet := GetLocationSnippetText(location); snippet != "" { snippets = append(snippets, snippet) } } return snippets } -func GetLocationSnippet(location *sarif.Location) string { +func GetLocationSnippetText(location *sarif.Location) string { + snippetContent := GetLocationSnippet(location) + if snippetContent != nil && snippetContent.Text != nil { + return *snippetContent.Text + } + return "" +} + +func GetLocationSnippet(location *sarif.Location) *sarif.ArtifactContent { region := getLocationRegion(location) if region != nil && region.Snippet != nil { - return *region.Snippet.Text + return region.Snippet } - return "" + return nil } func SetLocationSnippet(location *sarif.Location, snippet string) { diff --git a/utils/formats/sarifutils/sarifutils_test.go b/utils/formats/sarifutils/sarifutils_test.go index 6363b515..ee30cde2 100644 --- a/utils/formats/sarifutils/sarifutils_test.go +++ b/utils/formats/sarifutils/sarifutils_test.go @@ -207,7 +207,7 @@ func TestGetResultMsgText(t *testing.T) { } } -func TestGetLocationSnippet(t *testing.T) { +func TestGetLocationSnippetText(t *testing.T) { tests := []struct { location *sarif.Location expectedOutput string @@ -223,7 +223,7 @@ func TestGetLocationSnippet(t *testing.T) { } for _, test := range tests { - assert.Equal(t, test.expectedOutput, GetLocationSnippet(test.location)) + assert.Equal(t, test.expectedOutput, GetLocationSnippetText(test.location)) } } @@ -244,7 +244,7 @@ func TestSetLocationSnippet(t *testing.T) { for _, test := range tests { SetLocationSnippet(test.location, test.expectedOutput) - assert.Equal(t, test.expectedOutput, GetLocationSnippet(test.location)) + assert.Equal(t, test.expectedOutput, GetLocationSnippetText(test.location)) } } diff --git a/utils/formats/sarifutils/test_sarifutils.go b/utils/formats/sarifutils/test_sarifutils.go index 4e9f56f1..bbf0621e 100644 --- a/utils/formats/sarifutils/test_sarifutils.go +++ b/utils/formats/sarifutils/test_sarifutils.go @@ -12,11 +12,10 @@ func CreateRunWithDummyResults(results ...*sarif.Result) *sarif.Run { return createRunWithDummyResults("", results...) } -func CreateDummyDriver(toolName, infoURI string, rules ...*sarif.ReportingDescriptor) *sarif.ToolComponent { +func CreateDummyDriver(toolName string, rules ...*sarif.ReportingDescriptor) *sarif.ToolComponent { return &sarif.ToolComponent{ - Name: toolName, - InformationURI: &infoURI, - Rules: rules, + Name: toolName, + Rules: rules, } } @@ -25,7 +24,7 @@ func CreateRunNameWithResults(toolName string, results ...*sarif.Result) *sarif. } func createRunWithDummyResults(toolName string, results ...*sarif.Result) *sarif.Run { - run := sarif.NewRunWithInformationURI(toolName, "") + run := sarif.NewRun(*sarif.NewSimpleTool(toolName)) for _, result := range results { if result.RuleID != nil { run.AddRule(*result.RuleID) diff --git a/utils/results/common.go b/utils/results/common.go index 75b34cf3..295d143c 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -244,7 +244,7 @@ func getDirectComponentsAndImpactPaths(target string, impactPaths [][]services.I componentId := impactPath[impactPathIndex].ComponentId if _, exist := componentsMap[componentId]; !exist { compName, compVersion, _ := techutils.SplitComponentId(componentId) - componentsMap[componentId] = formats.ComponentRow{Name: compName, Version: compVersion, Location: getComponentLocation(target)} + componentsMap[componentId] = formats.ComponentRow{Name: compName, Version: compVersion, Location: getComponentLocation(impactPath[impactPathIndex].FullPath, target)} } // Convert the impact path @@ -252,8 +252,9 @@ func getDirectComponentsAndImpactPaths(target string, impactPaths [][]services.I for _, pathNode := range impactPath { nodeCompName, nodeCompVersion, _ := techutils.SplitComponentId(pathNode.ComponentId) compImpactPathRows = append(compImpactPathRows, formats.ComponentRow{ - Name: nodeCompName, - Version: nodeCompVersion, + Name: nodeCompName, + Version: nodeCompVersion, + Location: getComponentLocation(pathNode.FullPath), }) } impactPathsRows = append(impactPathsRows, compImpactPathRows) @@ -265,11 +266,13 @@ func getDirectComponentsAndImpactPaths(target string, impactPaths [][]services.I return } -func getComponentLocation(target string) *formats.Location { - if target == "" { - return nil +func getComponentLocation(pathsByPriority ...string) *formats.Location { + for _, path := range pathsByPriority { + if path != "" { + return &formats.Location{File: path} + } } - return &formats.Location{File: target} + return nil } func GetIssueIdentifier(cvesRow []formats.CveRow, issueId string, delimiter string) string { @@ -466,7 +469,7 @@ func GetCveApplicabilityField(cveId string, applicabilityScanResults []*sarif.Ru case len(applicability.Evidence) == 0: applicability.Status = string(jasutils.NotApplicable) default: - applicability.Status = string(jasutils.NotCovered) + applicability.Status = string(jasutils.Applicable) } return &applicability } @@ -483,7 +486,7 @@ func getEvidence(components map[string]services.Component, result *sarif.Result, StartColumn: sarifutils.GetLocationStartColumn(location), EndLine: sarifutils.GetLocationEndLine(location), EndColumn: sarifutils.GetLocationEndColumn(location), - Snippet: sarifutils.GetLocationSnippet(location), + Snippet: sarifutils.GetLocationSnippetText(location), }, Reason: sarifutils.GetResultMsgText(result), } diff --git a/utils/results/conversion/convertor.go b/utils/results/conversion/convertor.go index ab21bc28..73a37c3a 100644 --- a/utils/results/conversion/convertor.go +++ b/utils/results/conversion/convertor.go @@ -116,7 +116,7 @@ func parseScaResults[T interface{}](params ResultConvertParams, parser ResultsSt return } for _, scaResults := range targetScansResults.ScaResults.XrayResults { - actualTarget := targetScansResults.ScanTarget.Copy(getScaScanTarget(targetScansResults.ScaResults, targetScansResults.Target)) + actualTarget := getScaScanTarget(targetScansResults.ScaResults, targetScansResults.ScanTarget) var applicableRuns []*sarif.Run if jasEntitled && targetScansResults.JasResults != nil { applicableRuns = targetScansResults.JasResults.ApplicabilityScanResults @@ -148,7 +148,7 @@ func parseScaResults[T interface{}](params ResultConvertParams, parser ResultsSt } // Get the best match for the scan target in the sca results -func getScaScanTarget(scaResults *results.ScaScanResults, target string) string { +func getScaScanTarget(scaResults *results.ScaScanResults, target results.ScanTarget) results.ScanTarget { if scaResults == nil || len(scaResults.Descriptors) == 0 { // If No Sca scan or no descriptors discovered, use the scan target (build-scan, binary-scan...) return target @@ -157,12 +157,12 @@ func getScaScanTarget(scaResults *results.ScaScanResults, target string) string // This is for multi module projects where there are multiple sca results for the same target var bestMatch string for _, descriptor := range scaResults.Descriptors { - if strings.HasPrefix(descriptor, target) && (bestMatch == "" || len(descriptor) < len(bestMatch)) { + if strings.HasPrefix(descriptor, target.Target) && (bestMatch == "" || len(descriptor) < len(bestMatch)) { bestMatch = descriptor } } if bestMatch != "" { - return bestMatch + return target.Copy(bestMatch) } return target } diff --git a/utils/results/conversion/convertor_test.go b/utils/results/conversion/convertor_test.go index 5e44af73..94a25c91 100644 --- a/utils/results/conversion/convertor_test.go +++ b/utils/results/conversion/convertor_test.go @@ -42,8 +42,24 @@ func getAuditValidationParams() validations.ValidationParams { } } +// For Summary we count unique CVE finding (issueId), for SARIF and SimpleJson we count all findings (pair of issueId+impactedComponent) +// We have in the result 2 CVE with 2 impacted components each +func getDockerScanValidationParams(unique bool) validations.ValidationParams { + params := validations.ValidationParams{ + ExactResultsMatch: true, + Vulnerabilities: 11, + Applicable: 3, + NotApplicable: 3, + NotCovered: 1, + Undetermined: 1, + Secrets: 3, + } + return params +} + func TestConvertResults(t *testing.T) { auditInputResults := testUtils.ReadCmdScanResults(t, filepath.Join(testDataDir, "audit", "audit_results.json")) + dockerScanInputResults := testUtils.ReadCmdScanResults(t, filepath.Join(testDataDir, "dockerscan", "docker_results.json")) testCases := []struct { contentFormat conversionFormat @@ -65,11 +81,34 @@ func TestConvertResults(t *testing.T) { inputResults: auditInputResults, expectedContentPath: filepath.Join(testDataDir, "audit", "audit_summary.json"), }, + { + contentFormat: SimpleJson, + inputResults: dockerScanInputResults, + expectedContentPath: filepath.Join(testDataDir, "dockerscan", "docker_simple_json.json"), + }, + { + contentFormat: Sarif, + inputResults: dockerScanInputResults, + expectedContentPath: filepath.Join(testDataDir, "dockerscan", "docker_sarif.json"), + }, + { + contentFormat: Summary, + inputResults: dockerScanInputResults, + expectedContentPath: filepath.Join(testDataDir, "dockerscan", "docker_summary.json"), + }, } for _, testCase := range testCases { - t.Run(fmt.Sprintf("Convert to %s", testCase.contentFormat), func(t *testing.T) { - validationParams := getAuditValidationParams() + t.Run(fmt.Sprintf("%s convert to %s", testCase.inputResults.CmdType, testCase.contentFormat), func(t *testing.T) { + var validationParams validations.ValidationParams + switch testCase.inputResults.CmdType { + case utils.SourceCode: + validationParams = getAuditValidationParams() + case utils.DockerImage: + validationParams = getDockerScanValidationParams(testCase.contentFormat == Summary) + default: + t.Fatalf("Unsupported command type: %s", testCase.inputResults.CmdType) + } pretty := false if testCase.contentFormat == Sarif { pretty = true diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index dd7e47f9..ef79188c 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -418,15 +418,21 @@ func patchRunsToPassIngestionRules(cmdType utils.CommandType, subScanType utils. // Since we run in temp directories files should be relative // Patch by converting the file paths to relative paths according to the invocations convertPaths(cmdType, subScanType, runs...) + patchedRuns := []*sarif.Run{} + // Patch changes may alter the original run, so we will create a new run for each for _, run := range runs { + patched := sarifutils.CopyRunMetadata(run) if cmdType.IsTargetBinary() && subScanType == utils.SecretsScan { // Patch the tool name in case of binary scan - sarifutils.SetRunToolName(binarySecretScannerToolName, run) + sarifutils.SetRunToolName(binarySecretScannerToolName, patched) } - run.Tool.Driver.Rules = patchRules(cmdType, subScanType, run.Tool.Driver.Rules...) - run.Results = patchResults(cmdType, subScanType, target, run, run.Results...) + if patched.Tool.Driver != nil { + patched.Tool.Driver.Rules = patchRules(cmdType, subScanType, run.Tool.Driver.Rules...) + } + patched.Results = patchResults(cmdType, subScanType, target, run, run.Results...) + patchedRuns = append(patchedRuns, patched) } - return runs + return patchedRuns } func convertPaths(commandType utils.CommandType, subScanType utils.SubScanType, runs ...*sarif.Run) { @@ -448,37 +454,42 @@ func convertPaths(commandType utils.CommandType, subScanType utils.SubScanType, func patchDockerSecretLocations(result *sarif.Result) { for _, location := range result.Locations { algorithm, layerHash, relativePath := getLayerContentFromPath(sarifutils.GetLocationFileName(location)) - if layerHash != "" { - // Set Logical location kind "layer" with the layer hash - logicalLocation := sarifutils.NewLogicalLocation(layerHash, "layer") - if algorithm != "" { - logicalLocation.Properties = sarif.Properties(map[string]interface{}{"algorithm": algorithm}) - } - location.LogicalLocations = append(location.LogicalLocations, logicalLocation) - } - if relativePath != "" { - sarifutils.SetLocationFileName(location, relativePath) + if algorithm == "" || layerHash == "" || relativePath == "" { + continue } + // Set Logical location kind "layer" with the layer hash + logicalLocation := sarifutils.NewLogicalLocation(layerHash, "layer") + logicalLocation.Properties = sarif.Properties(map[string]interface{}{"algorithm": algorithm}) + location.LogicalLocations = append(location.LogicalLocations, logicalLocation) + sarifutils.SetLocationFileName(location, relativePath) } } func patchRules(commandType utils.CommandType, subScanType utils.SubScanType, rules ...*sarif.ReportingDescriptor) (patched []*sarif.ReportingDescriptor) { patched = []*sarif.ReportingDescriptor{} for _, rule := range rules { - // Github code scanning ingestion rules rejects rules without help content. - // Patch by transferring the full description to the help field. - if rule.Help == nil && rule.FullDescription != nil { - rule.Help = rule.FullDescription - } - // SARIF1001 - if both 'id' and 'name' are present, they must be different. If they are identical, the tool must omit the 'name' property. + cloned := sarif.NewRule(rule.ID) if rule.Name != nil && rule.ID == *rule.Name { - rule.Name = nil + // SARIF1001 - if both 'id' and 'name' are present, they must be different. If they are identical, the tool must omit the 'name' property. + cloned.Name = rule.Name } + cloned.ShortDescription = rule.ShortDescription if commandType.IsTargetBinary() && subScanType == utils.SecretsScan { // Patch the rule name in case of binary scan - sarifutils.SetRuleShortDescriptionText(fmt.Sprintf("[Secret in Binary found] %s", sarifutils.GetRuleShortDescriptionText(rule)), rule) + sarifutils.SetRuleShortDescriptionText(fmt.Sprintf("[Secret in Binary found] %s", sarifutils.GetRuleShortDescriptionText(rule)), cloned) } - patched = append(patched, rule) + cloned.FullDescription = rule.FullDescription + cloned.Help = rule.Help + if cloned.Help == nil { + // Github code scanning ingestion rules rejects rules without help content. + // Patch by transferring the full description to the help field. + cloned.Help = rule.FullDescription + } + cloned.HelpURI = rule.HelpURI + cloned.Properties = rule.Properties + cloned.MessageStrings = rule.MessageStrings + + patched = append(patched, cloned) } return } @@ -514,12 +525,17 @@ func patchResults(commandType utils.CommandType, subScanType utils.SubScanType, return patched } +// This method may need to replace the physical location if applicable, to avoid override on the existing object we will return a new object if changed func convertBinaryPhysicalLocations(commandType utils.CommandType, run *sarif.Run, result *sarif.Result) *sarif.Result { if patchedLocation := getPatchedBinaryLocation(commandType, run); patchedLocation != "" { - for _, location := range result.Locations { + patched := sarifutils.CopyResult(result) + for _, location := range patched.Locations { // Patch the location - Reset the uri and region location.PhysicalLocation = sarifutils.NewPhysicalLocation(patchedLocation) } + return patched + } else { + return result } } @@ -659,7 +675,7 @@ func getBinaryLocationMarkdownString(commandType utils.CommandType, subScanType if locationFilePath := sarifutils.GetLocationFileName(location); locationFilePath != "" { content += fmt.Sprintf("\nFilepath: %s", locationFilePath) } - if snippet := sarifutils.GetLocationSnippet(location); snippet != "" { + if snippet := sarifutils.GetLocationSnippetText(location); snippet != "" { content += fmt.Sprintf("\nEvidence: %s", snippet) } return diff --git a/utils/results/conversion/sarifparser/sarifparser_test.go b/utils/results/conversion/sarifparser/sarifparser_test.go index 2613954e..cda59799 100644 --- a/utils/results/conversion/sarifparser/sarifparser_test.go +++ b/utils/results/conversion/sarifparser/sarifparser_test.go @@ -408,14 +408,14 @@ func TestPatchRunsToPassIngestionRules(t *testing.T) { expectedResults: []*sarif.Run{ { Tool: sarif.Tool{ - Driver: sarifutils.CreateDummyDriver(binarySecretScannerToolName, "", &sarif.ReportingDescriptor{ + Driver: sarifutils.CreateDummyDriver(binarySecretScannerToolName, &sarif.ReportingDescriptor{ ID: "rule", ShortDescription: sarif.NewMultiformatMessageString("[Secret in Binary found] "), }), }, Invocations: []*sarif.Invocation{sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd))}, Results: []*sarif.Result{ - sarifutils.CreateDummyResultWithFingerprint(fmt.Sprintf("🔒 Found Secrets in Binary docker scanning:\nImage: dockerImage:imageVersion\nLayer (sha1): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: %s\nEvidence: snippet", filepath.Join("usr", "src", "app", "server", "index.js")), "", jfrogFingerprintAlgorithmName, "dee156c9fd75a4237102dc8fb29277a2", + sarifutils.CreateDummyResultWithFingerprint(fmt.Sprintf("🔒 Found Secrets in Binary docker scanning:\nImage: dockerImage:imageVersion\nLayer (sha1): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: %s\nEvidence: snippet", filepath.Join("usr", "src", "app", "server", "index.js")), "", jfrogFingerprintAlgorithmName, "93d660ebfd39b1220c42c0beb6e4e863", sarifutils.CreateDummyLocationWithPathAndLogicalLocation(filepath.Join("usr", "src", "app", "server", "index.js"), "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", "layer", "algorithm", "sha1"), ), }, @@ -493,8 +493,8 @@ func TestPatchRunsToPassIngestionRules(t *testing.T) { revertWd := clientTests.ChangeDirWithCallback(t, wd, dockerfileDir) defer revertWd() } - patchRunsToPassIngestionRules(tc.cmdType, tc.subScan, tc.target, tc.input...) - assert.ElementsMatch(t, tc.expectedResults, tc.input) + patchedRuns := patchRunsToPassIngestionRules(tc.cmdType, tc.subScan, tc.target, tc.input...) + assert.ElementsMatch(t, tc.expectedResults, patchedRuns) }) } } diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go index 727418fb..7bf22e47 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go @@ -312,7 +312,7 @@ func PrepareSimpleJsonJasIssues(entitledForJas, pretty bool, jasIssues ...*sarif StartColumn: sarifutils.GetLocationStartColumn(location), EndLine: sarifutils.GetLocationEndLine(location), EndColumn: sarifutils.GetLocationEndColumn(location), - Snippet: sarifutils.GetLocationSnippet(location), + Snippet: sarifutils.GetLocationSnippetText(location), }, CodeFlow: codeFlowToLocationFlow(sarifutils.GetLocationRelatedCodeFlowsFromResult(location, result), run.Invocations, pretty), }, @@ -337,7 +337,7 @@ func codeFlowToLocationFlow(flows []*sarif.CodeFlow, invocations []*sarif.Invoca StartColumn: sarifutils.GetLocationStartColumn(stackTraceEntry.Location), EndLine: sarifutils.GetLocationEndLine(stackTraceEntry.Location), EndColumn: sarifutils.GetLocationEndColumn(stackTraceEntry.Location), - Snippet: sarifutils.GetLocationSnippet(stackTraceEntry.Location), + Snippet: sarifutils.GetLocationSnippetText(stackTraceEntry.Location), }) } flowRows = append(flowRows, rowFlow) diff --git a/utils/results/conversion/tableparser/tableparser.go b/utils/results/conversion/tableparser/tableparser.go index fe2925f2..5383946f 100644 --- a/utils/results/conversion/tableparser/tableparser.go +++ b/utils/results/conversion/tableparser/tableparser.go @@ -28,7 +28,7 @@ func (tc *CmdResultsTableConverter) Get() (formats.ResultsTables, error) { } return formats.ResultsTables{ SecurityVulnerabilitiesTable: formats.ConvertToVulnerabilityTableRow(simpleJsonFormat.Vulnerabilities), - SecurityViolationsTable: formats.ConvertToVulnerabilityTableRow(simpleJsonFormat.SecurityViolations), + SecurityViolationsTable: formats.ConvertToVulnerabilityTableRow(simpleJsonFormat.SecurityViolations), LicenseViolationsTable: formats.ConvertToLicenseViolationTableRow(simpleJsonFormat.LicensesViolations), OperationalRiskViolationsTable: formats.ConvertToOperationalRiskViolationTableRow(simpleJsonFormat.OperationalRiskViolations), SecretsTable: formats.ConvertToSecretsTableRow(simpleJsonFormat.Secrets), diff --git a/utils/results/output/resultwriter.go b/utils/results/output/resultwriter.go index fe4243ec..42f1328f 100644 --- a/utils/results/output/resultwriter.go +++ b/utils/results/output/resultwriter.go @@ -15,7 +15,6 @@ import ( "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "github.com/jfrog/jfrog-client-go/utils/log" - "github.com/jfrog/jfrog-client-go/xray/services" "github.com/owenrumney/go-sarif/v2/sarif" ) @@ -34,8 +33,6 @@ type ResultsWriter struct { isMultipleRoots *bool // PrintExtended, If true, show extended results. printExtended bool - // The scanType (binary,dependency) - scanType services.ScanType // For table format - show table only for the given subScansPreformed subScansPreformed []utils.SubScanType // Messages - Option array of messages, to be displayed if the format is Table @@ -56,11 +53,6 @@ func (rw *ResultsWriter) SetIsMultipleRootProject(isMultipleRootProject bool) *R return rw } -func (rw *ResultsWriter) SetScanType(scanType services.ScanType) *ResultsWriter { - rw.scanType = scanType - return rw -} - func (rw *ResultsWriter) SetSubScansPreformed(subScansPreformed []utils.SubScanType) *ResultsWriter { rw.subScansPreformed = subScansPreformed return rw @@ -108,8 +100,8 @@ func isPrettyOutputSupported() bool { return log.IsStdOutTerminal() && log.IsColorsSupported() || os.Getenv("GITLAB_CI") != "" } -func shouldPrintTable(requestedScans []utils.SubScanType, subScan utils.SubScanType, scanType services.ScanType) bool { - if scanType == services.Binary && (subScan == utils.IacScan || subScan == utils.SastScan) { +func shouldPrintTable(requestedScans []utils.SubScanType, subScan utils.SubScanType, cmdType utils.CommandType) bool { + if cmdType.IsTargetBinary() && (subScan == utils.IacScan || subScan == utils.SastScan) { return false } return len(requestedScans) == 0 || slices.Contains(requestedScans, subScan) @@ -189,7 +181,7 @@ func (rw *ResultsWriter) printOrSaveRawResults(printMsg bool) (err error) { if printMsg && !utils.IsCI() { // Save the results to a file and print a link to it. var resultsPath string - if resultsPath, err = writeJsonResults(rw.commandResults); err != nil { + if resultsPath, err = WriteJsonResults(rw.commandResults); err != nil { return } printMessage(coreutils.PrintTitle("The full scan results are available here: ") + coreutils.PrintLink(resultsPath)) @@ -213,34 +205,34 @@ func (rw *ResultsWriter) printTables() (err error) { if err = rw.printOrSaveRawResults(true); err != nil { return } - if shouldPrintTable(rw.subScansPreformed, utils.ScaScan, rw.scanType) { + if shouldPrintTable(rw.subScansPreformed, utils.ScaScan, rw.commandResults.CmdType) { if rw.hasViolationContext { - if err = PrintViolationsTable(tableContent, rw.scanType, rw.printExtended); err != nil { + if err = PrintViolationsTable(tableContent, rw.commandResults.CmdType, rw.printExtended); err != nil { return } } if rw.includeVulnerabilities { - if err = PrintVulnerabilitiesTable(tableContent, rw.scanType, len(rw.commandResults.GetTechnologies()) > 0, rw.printExtended); err != nil { + if err = PrintVulnerabilitiesTable(tableContent, rw.commandResults.CmdType, len(rw.commandResults.GetTechnologies()) > 0, rw.printExtended); err != nil { return } } if rw.includeLicenses { - if err = PrintLicensesTable(tableContent, rw.printExtended, rw.scanType); err != nil { + if err = PrintLicensesTable(tableContent, rw.printExtended, rw.commandResults.CmdType); err != nil { return } } } - if shouldPrintTable(rw.subScansPreformed, utils.SecretsScan, rw.scanType) { + if shouldPrintTable(rw.subScansPreformed, utils.SecretsScan, rw.commandResults.CmdType) { if err = PrintJasTable(tableContent, rw.commandResults.EntitledForJas, jasutils.Secrets); err != nil { return } } - if shouldPrintTable(rw.subScansPreformed, utils.IacScan, rw.scanType) { + if shouldPrintTable(rw.subScansPreformed, utils.IacScan, rw.commandResults.CmdType) { if err = PrintJasTable(tableContent, rw.commandResults.EntitledForJas, jasutils.IaC); err != nil { return } } - if !shouldPrintTable(rw.subScansPreformed, utils.SastScan, rw.scanType) { + if !shouldPrintTable(rw.subScansPreformed, utils.SastScan, rw.commandResults.CmdType) { return nil } return PrintJasTable(tableContent, rw.commandResults.EntitledForJas, jasutils.Sast) @@ -249,10 +241,10 @@ func (rw *ResultsWriter) printTables() (err error) { // PrintVulnerabilitiesTable prints the vulnerabilities in a table. // Set printExtended to true to print fields with 'extended' tag. // If the scan argument is set to true, print the scan tables. -func PrintVulnerabilitiesTable(tables formats.ResultsTables, scanType services.ScanType, techDetected, printExtended bool) error { +func PrintVulnerabilitiesTable(tables formats.ResultsTables, cmdType utils.CommandType, techDetected, printExtended bool) error { // Space before the tables log.Output() - if scanType == services.Binary { + if cmdType.IsTargetBinary() { return coreutils.PrintTable(formats.ConvertSecurityTableRowToScanTableRow(tables.SecurityVulnerabilitiesTable), "Vulnerable Components", "✨ No vulnerable components were found ✨", @@ -269,10 +261,10 @@ func PrintVulnerabilitiesTable(tables formats.ResultsTables, scanType services.S // PrintViolationsTable prints the violations in 4 tables: security violations, license compliance violations, operational risk violations and ignore rule URLs. // Set printExtended to true to print fields with 'extended' tag. // If the scan argument is set to true, print the scan tables. -func PrintViolationsTable(tables formats.ResultsTables, scanType services.ScanType, printExtended bool) (err error) { +func PrintViolationsTable(tables formats.ResultsTables, cmdType utils.CommandType, printExtended bool) (err error) { // Space before the tables log.Output() - if scanType == services.Binary { + if cmdType.IsTargetBinary() { err = coreutils.PrintTable(formats.ConvertSecurityTableRowToScanTableRow(tables.SecurityViolationsTable), "Security Violations", "No security violations were found", printExtended) if err != nil { return err @@ -305,10 +297,10 @@ func PrintViolationsTable(tables formats.ResultsTables, scanType services.ScanTy // In case multipleRoots is true, the field Component will show the root of each impact path, otherwise it will show the root's child. // Set printExtended to true to print fields with 'extended' tag. // If the scan argument is set to true, print the scan tables. -func PrintLicensesTable(tables formats.ResultsTables, printExtended bool, scanType services.ScanType) error { +func PrintLicensesTable(tables formats.ResultsTables, printExtended bool, cmdType utils.CommandType) error { // Space before the tables log.Output() - if scanType == services.Binary { + if cmdType.IsTargetBinary() { return coreutils.PrintTable(formats.ConvertLicenseTableRowToScanTableRow(tables.LicensesTable), "Licenses", "No licenses were found", printExtended) } return coreutils.PrintTable(tables.LicensesTable, "Licenses", "No licenses were found", printExtended) @@ -334,7 +326,7 @@ func PrintJasTable(tables formats.ResultsTables, entitledForJas bool, scanType j return nil } -func writeJsonResults(results *results.SecurityCommandResults) (resultsPath string, err error) { +func WriteJsonResults(results *results.SecurityCommandResults) (resultsPath string, err error) { out, err := fileutils.CreateTempFile() if errorutils.CheckError(err) != nil { return diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index 8e0d4bd6..988b2cb6 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -13,8 +13,8 @@ import ( ) const ( - SastToolName = "USAF" - IacToolName = "JFrog Terraform scanner" + SastToolName = "USAF" + IacToolName = "JFrog Terraform scanner" // #nosec G101 -- Not credentials. SecretsToolName = "JFrog Secrets scanner" ) From 6c3a32c1e0ebdbc60c16034b9d64ee1461816295 Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 15 Sep 2024 15:48:35 +0300 Subject: [PATCH 56/82] fix merge --- utils/results/common.go | 6 +++++ utils/results/common_test.go | 26 ++++++++++++++----- .../sarifparser/sarifparser_test.go | 10 +++---- .../simplejsonparser/simplejsonparser.go | 1 + 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/utils/results/common.go b/utils/results/common.go index 295d143c..2ed13569 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -444,10 +444,12 @@ func GetCveApplicabilityField(cveId string, applicabilityScanResults []*sarif.Ru for _, applicabilityRun := range applicabilityScanResults { if rule, _ := applicabilityRun.GetRuleById(jasutils.CveToApplicabilityRuleId(cveId)); rule != nil { applicability.ScannerDescription = sarifutils.GetRuleFullDescription(rule) + applicability.UndeterminedReason = GetRuleUndeterminedReason(rule) status := getApplicabilityStatusFromRule(rule) if status != "" { applicabilityStatuses = append(applicabilityStatuses, status) } + } result, _ := applicabilityRun.GetResultByRuleId(jasutils.CveToApplicabilityRuleId(cveId)) if result == nil { @@ -508,6 +510,10 @@ func GetApplicableCveStatus(entitledForJas bool, applicabilityScanResults []*sar return getFinalApplicabilityStatus(applicableStatuses) } +func GetRuleUndeterminedReason(rule *sarif.ReportingDescriptor) string { + return sarifutils.GetRuleProperty("undetermined_reason", rule) +} + func getApplicabilityStatusFromRule(rule *sarif.ReportingDescriptor) jasutils.ApplicabilityStatus { if rule.Properties[jasutils.ApplicabilitySarifPropertyKey] != nil { status, ok := rule.Properties[jasutils.ApplicabilitySarifPropertyKey].(string) diff --git a/utils/results/common_test.go b/utils/results/common_test.go index 4dca1930..84830abf 100644 --- a/utils/results/common_test.go +++ b/utils/results/common_test.go @@ -464,9 +464,9 @@ func TestGetApplicableCveValue(t *testing.T) { name: "new scan statuses - applicable wins all statuses", entitledForJas: true, applicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", sarifutils.CreateDummyPassingResult("applic_testCve1")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_testCve2")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve3")), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve1"), []string{"applicability"}, []string{"applicable"}), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve2"), []string{"applicability"}, []string{"not_applicable"}), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve3"), []string{"applicability"}, []string{"not_covered"}), }, cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}, {Id: "testCve3"}}, expectedResult: jasutils.Applicable, @@ -480,8 +480,8 @@ func TestGetApplicableCveValue(t *testing.T) { name: "new scan statuses - not covered wins not applicable", entitledForJas: true, applicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve1")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_testCve2")), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve1"), []string{"applicability"}, []string{"not_covered"}), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve2"), []string{"applicability"}, []string{"not_applicable"}), }, cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, expectedResult: jasutils.NotCovered, @@ -494,8 +494,8 @@ func TestGetApplicableCveValue(t *testing.T) { name: "new scan statuses - undetermined wins not covered", entitledForJas: true, applicabilityScanResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "not_covered", sarifutils.CreateDummyPassingResult("applic_testCve1")), - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "undetermined", sarifutils.CreateDummyPassingResult("applic_testCve2")), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve1"), []string{"applicability"}, []string{"not_covered"}), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve2"), []string{"applicability"}, []string{"undetermined"}), }, cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, expectedResult: jasutils.ApplicabilityUndetermined, @@ -504,6 +504,18 @@ func TestGetApplicableCveValue(t *testing.T) { {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.ApplicabilityUndetermined)}}, }, }, + { + name: "undetermined with undetermined reason", + entitledForJas: true, + applicabilityScanResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve2"), []string{"applicability", "undetermined_reason"}, []string{"undetermined", "however"}), + }, + cves: []services.Cve{{Id: "testCve2"}}, + expectedResult: jasutils.ApplicabilityUndetermined, + expectedCves: []formats.CveRow{ + {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.ApplicabilityUndetermined.String(), UndeterminedReason: "however"}}, + }, + }, { name: "disqualified evidence", entitledForJas: true, diff --git a/utils/results/conversion/sarifparser/sarifparser_test.go b/utils/results/conversion/sarifparser/sarifparser_test.go index cda59799..479e051c 100644 --- a/utils/results/conversion/sarifparser/sarifparser_test.go +++ b/utils/results/conversion/sarifparser/sarifparser_test.go @@ -324,21 +324,21 @@ func TestPatchRunsToPassIngestionRules(t *testing.T) { cmdType: utils.DockerImage, subScan: utils.ScaScan, input: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg"))). + sarifutils.CreateRunWithDummyResultAndRuleProperties( + sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg"))). WithInvocations([]*sarif.Invocation{ sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd)), - }, - ), + }), sarifutils.CreateRunWithDummyResultsInWd(wd, sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg")), ), }, expectedResults: []*sarif.Run{ - sarifutils.CreateRunWithDummyResultAndRuleProperties("applicability", "applicable", + sarifutils.CreateRunWithDummyResultAndRuleProperties( sarifutils.CreateDummyResultWithFingerprint("some-msg\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "some-msg", jfrogFingerprintAlgorithmName, "9522c1d915eef55b4a0dc9e160bf5dc7", sarifutils.CreateDummyLocationWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256"), ), - ).WithInvocations([]*sarif.Invocation{ + []string{"applicability"}, []string{"applicable"}).WithInvocations([]*sarif.Invocation{ sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd)), }), sarifutils.CreateRunWithDummyResultsInWd(wd, diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go index 7bf22e47..4d6df490 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go @@ -306,6 +306,7 @@ func PrepareSimpleJsonJasIssues(entitledForJas, pretty bool, jasIssues ...*sarif SeverityDetails: severityutils.GetAsDetails(severity, jasutils.Applicable, pretty), Finding: sarifutils.GetResultMsgText(result), ScannerDescription: scannerDescription, + Fingerprint: sarifutils.GetResultFingerprint(result), Location: formats.Location{ File: sarifutils.GetRelativeLocationFileName(location, run.Invocations), StartLine: sarifutils.GetLocationStartLine(location), From 6815d23114f5d194a0d570c0b6cabe7062ef263e Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 15 Sep 2024 15:49:16 +0300 Subject: [PATCH 57/82] format --- .../results/conversion/sarifparser/sarifparser_test.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/utils/results/conversion/sarifparser/sarifparser_test.go b/utils/results/conversion/sarifparser/sarifparser_test.go index 479e051c..e98a5f9f 100644 --- a/utils/results/conversion/sarifparser/sarifparser_test.go +++ b/utils/results/conversion/sarifparser/sarifparser_test.go @@ -325,10 +325,8 @@ func TestPatchRunsToPassIngestionRules(t *testing.T) { subScan: utils.ScaScan, input: []*sarif.Run{ sarifutils.CreateRunWithDummyResultAndRuleProperties( - sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg"))). - WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd)), - }), + sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg")), + []string{"applicability"}, []string{"applicable"}).WithInvocations([]*sarif.Invocation{sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd))}), sarifutils.CreateRunWithDummyResultsInWd(wd, sarifutils.CreateDummyResultWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithMessage(sarif.NewTextMessage("some-msg")), ), @@ -338,9 +336,7 @@ func TestPatchRunsToPassIngestionRules(t *testing.T) { sarifutils.CreateDummyResultWithFingerprint("some-msg\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "some-msg", jfrogFingerprintAlgorithmName, "9522c1d915eef55b4a0dc9e160bf5dc7", sarifutils.CreateDummyLocationWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256"), ), - []string{"applicability"}, []string{"applicable"}).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd)), - }), + []string{"applicability"}, []string{"applicable"}).WithInvocations([]*sarif.Invocation{sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation(wd))}), sarifutils.CreateRunWithDummyResultsInWd(wd, sarifutils.CreateDummyResultWithFingerprint("some-msg\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "some-msg", jfrogFingerprintAlgorithmName, "9522c1d915eef55b4a0dc9e160bf5dc7", sarifutils.CreateDummyLocationWithPathAndLogicalLocation("sha256__f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256"), From 650547f41312311e3bf0cef1f3d20a9655fa818e Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 15 Sep 2024 16:30:56 +0300 Subject: [PATCH 58/82] fix static --- .../simplejsonparser/simplejsonparser_test.go | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go index e3394056..04a24886 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go @@ -337,15 +337,13 @@ func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { entitledForJas: true, applicabilityRuns: []*sarif.Run{ sarifutils.CreateRunWithDummyResultAndRuleProperties( - "applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_CVE-1"), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target")), - }), + sarifutils.CreateDummyPassingResult("applic_CVE-1"), + []string{"applicability"}, []string{"not_applicable"}, + ).WithInvocations([]*sarif.Invocation{sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target"))}), sarifutils.CreateRunWithDummyResultAndRuleProperties( - "applicability", "applicable", sarifutils.CreateResultWithLocations("applic_CVE-2", "applic_CVE-2", "note", sarifutils.CreateLocation("target/file", 0, 0, 0, 0, "snippet")), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target")), - }), + sarifutils.CreateResultWithLocations("applic_CVE-2", "applic_CVE-2", "note", sarifutils.CreateLocation("target/file", 0, 0, 0, 0, "snippet")), + []string{"applicability"}, []string{"applicable"}, + ).WithInvocations([]*sarif.Invocation{sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target"))}), }, expectedOutput: []formats.VulnerabilityOrViolationRow{ { @@ -502,15 +500,13 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { entitledForJas: true, applicabilityRuns: []*sarif.Run{ sarifutils.CreateRunWithDummyResultAndRuleProperties( - "applicability", "not_applicable", sarifutils.CreateDummyPassingResult("applic_CVE-1"), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target")), - }), + sarifutils.CreateDummyPassingResult("applic_CVE-1"), + []string{"applicability"}, []string{"not_applicable"}, + ).WithInvocations([]*sarif.Invocation{sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target"))}), sarifutils.CreateRunWithDummyResultAndRuleProperties( - "applicability", "applicable", sarifutils.CreateResultWithLocations("applic_CVE-2", "applic_CVE-2", "note", sarifutils.CreateLocation("target/file", 0, 0, 0, 0, "snippet")), - ).WithInvocations([]*sarif.Invocation{ - sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target")), - }), + sarifutils.CreateResultWithLocations("applic_CVE-2", "applic_CVE-2", "note", sarifutils.CreateLocation("target/file", 0, 0, 0, 0, "snippet")), + []string{"applicability"}, []string{"applicable"}, + ).WithInvocations([]*sarif.Invocation{sarif.NewInvocation().WithWorkingDirectory(sarif.NewSimpleArtifactLocation("target"))}), }, expectedSecurityOutput: []formats.VulnerabilityOrViolationRow{ { From 9e206529974b839ae0266240cfa95d1c23cdfaa3 Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 15 Sep 2024 17:13:07 +0300 Subject: [PATCH 59/82] merge --- commands/audit/audit.go | 2 +- commands/audit/audit_test.go | 1 - jas/runner/jasrunner.go | 13 ++++++++----- utils/utils.go | 1 - 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/commands/audit/audit.go b/commands/audit/audit.go index 13a7b74e..1e715bb8 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -11,10 +11,10 @@ import ( "github.com/jfrog/jfrog-cli-security/jas/applicability" "github.com/jfrog/jfrog-cli-security/jas/runner" "github.com/jfrog/jfrog-cli-security/jas/secrets" + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/results/output" "github.com/jfrog/jfrog-cli-security/utils/techutils" - "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/xray/scangraph" "github.com/jfrog/jfrog-cli-security/utils/xsc" diff --git a/commands/audit/audit_test.go b/commands/audit/audit_test.go index 6b3a577a..e9fc4cc6 100644 --- a/commands/audit/audit_test.go +++ b/commands/audit/audit_test.go @@ -1,7 +1,6 @@ package audit import ( - "os" "path/filepath" "sort" "testing" diff --git a/jas/runner/jasrunner.go b/jas/runner/jasrunner.go index 660f91c6..423c4698 100644 --- a/jas/runner/jasrunner.go +++ b/jas/runner/jasrunner.go @@ -3,6 +3,8 @@ package runner import ( "encoding/json" "fmt" + "path/filepath" + "github.com/jfrog/gofrog/parallel" jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" "github.com/jfrog/jfrog-cli-core/v2/utils/config" @@ -38,9 +40,10 @@ type JasRunnerParams struct { ApplicableScanType applicability.ApplicabilityScanType ScanResults *results.TargetResults + TargetOutputDir string } -func AddJasScannersTasks(params JasRunnerParams, scansOutputDir string) (err error) { +func AddJasScannersTasks(params JasRunnerParams) (err error) { if params.ServerDetails == nil || len(params.ServerDetails.Url) == 0 { log.Warn("To include 'Advanced Security' scan as part of the audit output, please run the 'jf c add' command before running this command.") return @@ -50,23 +53,23 @@ func AddJasScannersTasks(params JasRunnerParams, scansOutputDir string) (err err if params.ApplicableScanType == applicability.ApplicabilityScannerType || params.SecretsScanType == secrets.SecretsScannerType { runAllScanners = true } - if err = addJasScanTaskForModuleIfNeeded(params, utils.ContextualAnalysisScan, runContextualScan(params.Runner, params.Scanner, params.ScanResults, params.Module, params.DirectDependencies, params.ThirdPartyApplicabilityScan, params.ApplicableScanType)); err != nil { + if err = addJasScanTaskForModuleIfNeeded(params, utils.ContextualAnalysisScan, runContextualScan(params.Runner, params.Scanner, params.ScanResults, params.Module, params.DirectDependencies, params.ThirdPartyApplicabilityScan, params.ApplicableScanType, params.TargetOutputDir)); err != nil { return } if params.ThirdPartyApplicabilityScan { // Don't execute other scanners when scanning third party dependencies. return } - if err = addJasScanTaskForModuleIfNeeded(params, utils.SecretsScan, runSecretsScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module, params.SecretsScanType)); err != nil { + if err = addJasScanTaskForModuleIfNeeded(params, utils.SecretsScan, runSecretsScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module, params.SecretsScanType, params.TargetOutputDir)); err != nil { return } if !runAllScanners { return } - if err = addJasScanTaskForModuleIfNeeded(params, utils.IacScan, runIacScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module)); err != nil { + if err = addJasScanTaskForModuleIfNeeded(params, utils.IacScan, runIacScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module, params.TargetOutputDir)); err != nil { return } - return addJasScanTaskForModuleIfNeeded(params, utils.SastScan, runSastScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module)) + return addJasScanTaskForModuleIfNeeded(params, utils.SastScan, runSastScan(params.Runner, params.Scanner, params.ScanResults.JasResults, params.Module, params.TargetOutputDir)) } func addJasScanTaskForModuleIfNeeded(params JasRunnerParams, subScan utils.SubScanType, task parallel.TaskFunc) (err error) { diff --git a/utils/utils.go b/utils/utils.go index dfdb82fb..3be26645 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -6,7 +6,6 @@ import ( "encoding/hex" "encoding/json" "fmt" - "os" "github.com/jfrog/jfrog-client-go/utils/log" "os" "path/filepath" From 6d952909f188c9d2be8cdd1fb838dd44ff08b1af Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 15 Sep 2024 17:19:42 +0300 Subject: [PATCH 60/82] fix conflict --- commands/audit/audit.go | 3 +- commands/audit/audit_test.go | 55 ++---------------------------------- commands/scan/buildscan.go | 2 +- jas/runner/jasrunner.go | 13 ++++----- 4 files changed, 12 insertions(+), 61 deletions(-) diff --git a/commands/audit/audit.go b/commands/audit/audit.go index 1e715bb8..a4bb735d 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -280,8 +280,9 @@ func downloadAnalyzerManagerAndRunScanners(auditParallelRunner *utils.SecurityPa ThirdPartyApplicabilityScan: auditParams.thirdPartyApplicabilityScan, ApplicableScanType: applicability.ApplicabilityScannerType, ScanResults: scan, + TargetOutputDir: auditParams.scanResultsOutputDir, } - if err = runner.AddJasScannersTasks(params, auditParams.scanResultsOutputDir); err != nil { + if err = runner.AddJasScannersTasks(params); err != nil { return fmt.Errorf("%s failed to run JAS scanners: %s", clientutils.GetLogMsgPrefix(threadId, false), err.Error()) } } diff --git a/commands/audit/audit_test.go b/commands/audit/audit_test.go index e9fc4cc6..eb36783b 100644 --- a/commands/audit/audit_test.go +++ b/commands/audit/audit_test.go @@ -3,6 +3,7 @@ package audit import ( "path/filepath" "sort" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -306,7 +307,7 @@ func TestAuditWithConfigProfile(t *testing.T) { // This test tests audit flow when providing --output-dir flag func TestAuditWithScansOutputDir(t *testing.T) { - mockServer, serverDetails := utils.XrayServer(t, utils.EntitlementsMinVersion) + mockServer, serverDetails := validations.XrayServer(t, utils.EntitlementsMinVersion) defer mockServer.Close() outputDirPath, removeOutputDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t) @@ -328,57 +329,7 @@ func TestAuditWithScansOutputDir(t *testing.T) { SetCommonGraphScanParams(&scangraph.CommonGraphScanParams{ ScanType: scanservices.Dependency, IncludeVulnerabilities: true, - MultiScanId: utils.TestScaScanId, - }). - SetScansResultsOutputDir(outputDirPath) - auditParams.SetIsRecursiveScan(true) - - _, err := RunAudit(auditParams) - assert.NoError(t, err) - - filesList, err := fileutils.ListFiles(outputDirPath, false) - assert.NoError(t, err) - assert.Len(t, filesList, 5) - - var fileNamesWithoutSuffix []string - for _, fileName := range filesList { - // Removing .json suffix to so we can check by suffix all expected files exist - splitName := strings.Split(fileName, "_") - fileNamesWithoutSuffix = append(fileNamesWithoutSuffix, splitName[0]) - } - - assert.Contains(t, fileNamesWithoutSuffix, filepath.Join(outputDirPath, "sca")) - assert.Contains(t, fileNamesWithoutSuffix, filepath.Join(outputDirPath, "iac")) - assert.Contains(t, fileNamesWithoutSuffix, filepath.Join(outputDirPath, "sast")) - assert.Contains(t, fileNamesWithoutSuffix, filepath.Join(outputDirPath, "secrets")) - assert.Contains(t, fileNamesWithoutSuffix, filepath.Join(outputDirPath, "applicability")) -} - -// This test tests audit flow when providing --output-dir flag -func TestAuditWithScansOutputDir(t *testing.T) { - mockServer, serverDetails := utils.XrayServer(t, utils.EntitlementsMinVersion) - defer mockServer.Close() - - outputDirPath, removeOutputDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t) - defer removeOutputDirCallback() - - tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t) - defer createTempDirCallback() - testDirPath := filepath.Join("..", "..", "tests", "testdata", "projects", "jas", "jas") - assert.NoError(t, biutils.CopyDir(testDirPath, tempDirPath, true, nil)) - - auditBasicParams := (&utils.AuditBasicParams{}). - SetServerDetails(serverDetails). - SetOutputFormat(format.Table). - SetUseJas(true) - - auditParams := NewAuditParams(). - SetWorkingDirs([]string{tempDirPath}). - SetGraphBasicParams(auditBasicParams). - SetCommonGraphScanParams(&scangraph.CommonGraphScanParams{ - ScanType: scanservices.Dependency, - IncludeVulnerabilities: true, - MultiScanId: utils.TestScaScanId, + MultiScanId: validations.TestScaScanId, }). SetScansResultsOutputDir(outputDirPath) auditParams.SetIsRecursiveScan(true) diff --git a/commands/scan/buildscan.go b/commands/scan/buildscan.go index db1a11d5..2b45a9c0 100644 --- a/commands/scan/buildscan.go +++ b/commands/scan/buildscan.go @@ -113,7 +113,7 @@ func (bsc *BuildScanCommand) Run() (err error) { return err } // If failBuild flag is true and also got fail build response from Xray - if bsc.failBuild && bsc.hasViolationContext() && isFailBuildResponse { + if bsc.failBuild && isFailBuildResponse { return results.NewFailBuildError() } return diff --git a/jas/runner/jasrunner.go b/jas/runner/jasrunner.go index 423c4698..8e69afe8 100644 --- a/jas/runner/jasrunner.go +++ b/jas/runner/jasrunner.go @@ -3,7 +3,6 @@ package runner import ( "encoding/json" "fmt" - "path/filepath" "github.com/jfrog/gofrog/parallel" jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" @@ -39,8 +38,8 @@ type JasRunnerParams struct { ThirdPartyApplicabilityScan bool ApplicableScanType applicability.ApplicabilityScanType - ScanResults *results.TargetResults - TargetOutputDir string + ScanResults *results.TargetResults + TargetOutputDir string } func AddJasScannersTasks(params JasRunnerParams) (err error) { @@ -132,9 +131,9 @@ func runSecretsScan(securityParallelRunner *utils.SecurityParallelRunner, scanne return fmt.Errorf("%s%s", clientutils.GetLogMsgPrefix(threadId, false), err.Error()) } securityParallelRunner.ResultsMu.Lock() + defer securityParallelRunner.ResultsMu.Unlock() extendedScanResults.SecretsScanResults = append(extendedScanResults.SecretsScanResults, results...) err = dumpSarifRunToFileIfNeeded(results, scansOutputDir, jasutils.Secrets) - securityParallelRunner.ResultsMu.Unlock() return } } @@ -150,9 +149,9 @@ func runIacScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *j return fmt.Errorf("%s %s", clientutils.GetLogMsgPrefix(threadId, false), err.Error()) } securityParallelRunner.ResultsMu.Lock() + defer securityParallelRunner.ResultsMu.Unlock() extendedScanResults.IacScanResults = append(extendedScanResults.IacScanResults, results...) err = dumpSarifRunToFileIfNeeded(results, scansOutputDir, jasutils.IaC) - securityParallelRunner.ResultsMu.Unlock() return } } @@ -168,9 +167,9 @@ func runSastScan(securityParallelRunner *utils.SecurityParallelRunner, scanner * return fmt.Errorf("%s %s", clientutils.GetLogMsgPrefix(threadId, false), err.Error()) } securityParallelRunner.ResultsMu.Lock() + defer securityParallelRunner.ResultsMu.Unlock() extendedScanResults.SastScanResults = append(extendedScanResults.SastScanResults, results...) err = dumpSarifRunToFileIfNeeded(results, scansOutputDir, jasutils.Sast) - securityParallelRunner.ResultsMu.Unlock() return } } @@ -188,9 +187,9 @@ func runContextualScan(securityParallelRunner *utils.SecurityParallelRunner, sca return fmt.Errorf("%s %s", clientutils.GetLogMsgPrefix(threadId, false), err.Error()) } securityParallelRunner.ResultsMu.Lock() + defer securityParallelRunner.ResultsMu.Unlock() scanResults.JasResults.ApplicabilityScanResults = append(scanResults.JasResults.ApplicabilityScanResults, results...) err = dumpSarifRunToFileIfNeeded(results, scansOutputDir, jasutils.Applicability) - securityParallelRunner.ResultsMu.Unlock() return } } From 7952aee42b154a635a54a8f0eee539808c3a8a8e Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 23 Sep 2024 17:49:55 +0300 Subject: [PATCH 61/82] continue merge --- audit_test.go | 4 +- commands/audit/audit.go | 13 ++-- commands/audit/audit_test.go | 4 -- commands/scan/scan.go | 2 +- jas/common.go | 14 ++--- scans_test.go | 2 +- utils/formats/sarifutils/sarifutils.go | 28 +++------ utils/jasutils/jasutils.go | 2 +- utils/results/common.go | 20 ++++++ utils/results/common_test.go | 33 ++++++++-- .../conversion/sarifparser/sarifparser.go | 7 ++- .../simplejsonparser/simplejsonparser.go | 15 ++++- utils/results/output/resultwriter.go | 15 ++++- utils/results/results.go | 11 ++-- utils/validations/test_validate_sarif.go | 54 ++++++++-------- utils/validations/test_validate_sca.go | 38 +++++------- .../validations/test_validate_simple_json.go | 62 +++++++++---------- utils/validations/test_validate_summary.go | 49 +++++---------- utils/validations/test_validation.go | 25 ++++++++ utils/xsc/analyticsmetrics_test.go | 2 +- 20 files changed, 231 insertions(+), 169 deletions(-) diff --git a/audit_test.go b/audit_test.go index 9869b926..ca03bade 100644 --- a/audit_test.go +++ b/audit_test.go @@ -556,7 +556,7 @@ func TestXrayAuditJasSimpleJson(t *testing.T) { func TestXrayAuditJasSimpleJsonWithTokenValidation(t *testing.T) { securityTestUtils.InitSecurityTest(t, jasutils.DynamicTokenValidationMinXrayVersion) output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("jas", "jas"), "3", true) - validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{Inactive:5}) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{Inactive: 5}) } func TestXrayAuditJasSimpleJsonWithOneThread(t *testing.T) { @@ -589,7 +589,7 @@ func TestXrayAuditJasSimpleJsonWithConfig(t *testing.T) { func TestXrayAuditJasNoViolationsSimpleJson(t *testing.T) { output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("package-managers", "npm", "npm"), "3", false) - validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, NotApplicable: 1}) + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{Vulnerabilities: 1, NotApplicable: 1}) } func testXrayAuditJas(t *testing.T, testCli *coreTests.JfrogCli, project string, threads string, validateSecrets bool) string { diff --git a/commands/audit/audit.go b/commands/audit/audit.go index be8b8a12..86446f2d 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -3,6 +3,7 @@ package audit import ( "errors" "fmt" + jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" @@ -190,7 +191,11 @@ func RunAudit(auditParams *AuditParams) (cmdResults *results.SecurityCommandResu return } // Initialize Results struct - cmdResults = initCmdResults(entitledForJas, auditParams) + cmdResults = initCmdResults( + entitledForJas, + jas.CheckForSecretValidation(xrayManager, auditParams.xrayVersion, slices.Contains(auditParams.AuditBasicParams.ScansToPerform(), utils.SecretTokenValidationScan)), + auditParams, + ) jfrogAppsConfig, err := jas.CreateJFrogAppsConfig(cmdResults.GetTargetsPaths()) if err != nil { return cmdResults, fmt.Errorf("failed to create JFrogAppsConfig: %s", err.Error()) @@ -257,7 +262,7 @@ func downloadAnalyzerManagerAndRunScanners(auditParallelRunner *utils.SecurityPa return fmt.Errorf("%s failed to download analyzer manager: %s", clientutils.GetLogMsgPrefix(threadId, false), err.Error()) } auditParallelRunner.ResultsMu.Lock() - scanner, err = jas.CreateJasScanner(scanner, serverDetails, jas.GetAnalyzerManagerXscEnvVars(auditParams.commonGraphScanParams.MultiScanId, scanResults.ExtendedScanResults.SecretValidation, scanResults.GetTechnologies()...), auditParams.Exclusions()...) + scanner, err = jas.CreateJasScanner(scanner, serverDetails, scanResults.SecretValidation, jas.GetAnalyzerManagerXscEnvVars(auditParams.commonGraphScanParams.MultiScanId, scanResults.GetTechnologies()...), auditParams.Exclusions()...) auditParallelRunner.ResultsMu.Unlock() if err != nil { return fmt.Errorf("failed to create jas scanner: %s", err.Error()) @@ -290,8 +295,8 @@ func downloadAnalyzerManagerAndRunScanners(auditParallelRunner *utils.SecurityPa return } -func initCmdResults(entitledForJas bool, params *AuditParams) (cmdResults *results.SecurityCommandResults) { - cmdResults = results.NewCommandResults(utils.SourceCode, params.xrayVersion, entitledForJas).SetMultiScanId(params.commonGraphScanParams.MultiScanId) +func initCmdResults(entitledForJas, secretValidation bool, params *AuditParams) (cmdResults *results.SecurityCommandResults) { + cmdResults = results.NewCommandResults(utils.SourceCode, params.xrayVersion, entitledForJas, secretValidation).SetMultiScanId(params.commonGraphScanParams.MultiScanId) detectScanTargets(cmdResults, params) scanInfo, err := coreutils.GetJsonIndent(cmdResults) if err != nil { diff --git a/commands/audit/audit_test.go b/commands/audit/audit_test.go index 103ffbb9..23d20b40 100644 --- a/commands/audit/audit_test.go +++ b/commands/audit/audit_test.go @@ -15,10 +15,6 @@ import ( "github.com/jfrog/jfrog-cli-security/utils/validations" "github.com/jfrog/jfrog-cli-security/utils/xray/scangraph" - "path/filepath" - "strings" - "testing" - biutils "github.com/jfrog/build-info-go/utils" "github.com/jfrog/jfrog-cli-core/v2/common/format" diff --git a/commands/scan/scan.go b/commands/scan/scan.go index c7747df3..fff53fb1 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -67,7 +67,7 @@ type ScanCommand struct { includeLicenses bool fail bool printExtendedTable bool - validateSecrets bool + validateSecrets bool bypassArchiveLimits bool fixableOnly bool progress ioUtils.ProgressMgr diff --git a/jas/common.go b/jas/common.go index d7e7fbf4..cca17773 100644 --- a/jas/common.go +++ b/jas/common.go @@ -40,12 +40,12 @@ type JasScanner struct { Exclusions []string } -func CreateJasScanner(scanner *JasScanner, serverDetails *config.ServerDetails, secretTokenValidation bool, envVars map[string]string, exclusions ...string) (*JasScanner, error) { +func CreateJasScanner(scanner *JasScanner, serverDetails *config.ServerDetails, validateSecrets bool, envVars map[string]string, exclusions ...string) (*JasScanner, error) { var err error if scanner.AnalyzerManager.AnalyzerManagerFullPath, err = GetAnalyzerManagerExecutable(); err != nil { return scanner, err } - if scanner.EnvVars, err = getJasEnvVars(serverDetails, secretTokenValidation, envVars); err != nil { + if scanner.EnvVars, err = getJasEnvVars(serverDetails, validateSecrets, envVars); err != nil { return scanner, err } var tempDir string @@ -61,11 +61,12 @@ func CreateJasScanner(scanner *JasScanner, serverDetails *config.ServerDetails, return scanner, err } -func getJasEnvVars(serverDetails *config.ServerDetails, secretTokenValidation bool, vars map[string]string) (map[string]string, error) { - amBasicVars, err := GetAnalyzerManagerEnvVariables(serverDetails, secretTokenValidation) +func getJasEnvVars(serverDetails *config.ServerDetails, validateSecrets bool, vars map[string]string) (map[string]string, error) { + amBasicVars, err := GetAnalyzerManagerEnvVariables(serverDetails) if err != nil { return nil, err } + amBasicVars[JfSecretValidationEnvVariable] = strconv.FormatBool(validateSecrets) return utils.MergeMaps(utils.ToEnvVarsMap(os.Environ()), amBasicVars, vars), nil } @@ -212,7 +213,7 @@ var FakeBasicXrayResults = []services.ScanResponse{ func InitJasTest(t *testing.T) (*JasScanner, func()) { assert.NoError(t, DownloadAnalyzerManagerIfNeeded(0)) scanner := &JasScanner{} - scanner, err := CreateJasScanner(scanner, &FakeServerDetails, GetAnalyzerManagerXscEnvVars("", false)) + scanner, err := CreateJasScanner(scanner, &FakeServerDetails, false, GetAnalyzerManagerXscEnvVars("")) assert.NoError(t, err) return scanner, func() { assert.NoError(t, scanner.ScannerDirCleanupFunc()) @@ -296,9 +297,8 @@ func CheckForSecretValidation(xrayManager *xray.XrayServicesManager, xrayVersion return err == nil && isEnabled } -func GetAnalyzerManagerXscEnvVars(msi string, validateSecrets bool, technologies ...techutils.Technology) map[string]string { +func GetAnalyzerManagerXscEnvVars(msi string, technologies ...techutils.Technology) map[string]string { envVars := map[string]string{utils.JfMsiEnvVariable: msi} - envVars[JfSecretValidationEnvVariable] = strconv.FormatBool(validateSecrets) if len(technologies) != 1 { return envVars } diff --git a/scans_test.go b/scans_test.go index d6d4d538..939a6e67 100644 --- a/scans_test.go +++ b/scans_test.go @@ -184,7 +184,7 @@ func runDockerScan(t *testing.T, testCli *coreTests.JfrogCli, imageName, watchNa if validateSecrets { validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{Inactive: minInactives}) } else { - validations.VerifyJsonResults(t, output, validations.ValidationParams{Vulnerabilities: minVulnerabilities, Licenses: minLicenses,}) + validations.VerifyJsonResults(t, output, validations.ValidationParams{Vulnerabilities: minVulnerabilities, Licenses: minLicenses}) } } // Run docker scan on image with watch diff --git a/utils/formats/sarifutils/sarifutils.go b/utils/formats/sarifutils/sarifutils.go index 57122bcd..05604f84 100644 --- a/utils/formats/sarifutils/sarifutils.go +++ b/utils/formats/sarifutils/sarifutils.go @@ -222,17 +222,6 @@ func AggregateMultipleRunsIntoSingle(runs []*sarif.Run, destination *sarif.Run) } } -func GetResultProperty(key string, result *sarif.Result) string { - if result != nil && result.Properties != nil && result.Properties[key] != nil { - status, ok := result.Properties[key].(string) - if !ok { - return "" - } - return status - } - return "" -} - func GetLocationRelatedCodeFlowsFromResult(location *sarif.Location, result *sarif.Result) (codeFlows []*sarif.CodeFlow) { for _, codeFlow := range result.CodeFlows { for _, stackTrace := range codeFlow.ThreadFlows { @@ -382,16 +371,17 @@ func GetResultRuleId(result *sarif.Result) string { return "" } -func GetResultProperty(key string, result *sarif.Result) string { - if result.Properties == nil { - return "" +func GetResultProperty(key string, result *sarif.Result) (value string) { + if result == nil || result.Properties == nil { + return } - if _, exists := result.Properties[key]; exists { - if value, ok := result.Properties[key].(string); ok { - return value - } + if _, exists := result.Properties[key]; !exists { + return } - return "" + if value, ok := result.Properties[key].(string); ok { + return value + } + return } func IsFingerprintsExists(result *sarif.Result) bool { diff --git a/utils/jasutils/jasutils.go b/utils/jasutils/jasutils.go index 2c40bff7..3c2d11c8 100644 --- a/utils/jasutils/jasutils.go +++ b/utils/jasutils/jasutils.go @@ -12,7 +12,7 @@ const ( ApplicabilitySarifPropertyKey = "applicability" DynamicTokenValidationMinXrayVersion = "3.101.0" - TokenValidationStatusForNonTokens = "Not a token" + TokenValidationStatusForNonTokens = "Not a token" ) const ( diff --git a/utils/results/common.go b/utils/results/common.go index 2ed13569..7b73421a 100644 --- a/utils/results/common.go +++ b/utils/results/common.go @@ -514,6 +514,14 @@ func GetRuleUndeterminedReason(rule *sarif.ReportingDescriptor) string { return sarifutils.GetRuleProperty("undetermined_reason", rule) } +func GetResultPropertyTokenValidation(result *sarif.Result) string { + return sarifutils.GetResultProperty("tokenValidation", result) +} + +func GetResultPropertyMetadata(result *sarif.Result) string { + return sarifutils.GetResultProperty("metadata", result) +} + func getApplicabilityStatusFromRule(rule *sarif.ReportingDescriptor) jasutils.ApplicabilityStatus { if rule.Properties[jasutils.ApplicabilitySarifPropertyKey] != nil { status, ok := rule.Properties[jasutils.ApplicabilitySarifPropertyKey].(string) @@ -529,6 +537,8 @@ func getApplicabilityStatusFromRule(rule *sarif.ReportingDescriptor) jasutils.Ap return jasutils.NotApplicable case "applicable": return jasutils.Applicable + case "missing_context": + return jasutils.MissingContext } } return "" @@ -576,6 +586,7 @@ func shouldDisqualifyEvidence(components map[string]services.Component, evidence // If we don't get any statues it means the applicability scanner didn't run -> final value is not scanned // If at least one cve is applicable -> final value is applicable // Else if at least one cve is undetermined -> final value is undetermined +// Else if at least one cve is missing context -> final value is missing context // Else if all cves are not covered -> final value is not covered // Else (case when all cves aren't applicable) -> final value is not applicable func getFinalApplicabilityStatus(applicabilityStatuses []jasutils.ApplicabilityStatus) jasutils.ApplicabilityStatus { @@ -583,6 +594,7 @@ func getFinalApplicabilityStatus(applicabilityStatuses []jasutils.ApplicabilityS return jasutils.NotScanned } foundUndetermined := false + foundMissingContext := false foundNotCovered := false for _, status := range applicabilityStatuses { if status == jasutils.Applicable { @@ -591,15 +603,23 @@ func getFinalApplicabilityStatus(applicabilityStatuses []jasutils.ApplicabilityS if status == jasutils.ApplicabilityUndetermined { foundUndetermined = true } + if status == jasutils.MissingContext { + foundMissingContext = true + } if status == jasutils.NotCovered { foundNotCovered = true } + } if foundUndetermined { return jasutils.ApplicabilityUndetermined } + if foundMissingContext { + return jasutils.MissingContext + } if foundNotCovered { return jasutils.NotCovered } + return jasutils.NotApplicable } diff --git a/utils/results/common_test.go b/utils/results/common_test.go index 84830abf..62607fac 100644 --- a/utils/results/common_test.go +++ b/utils/results/common_test.go @@ -406,6 +406,16 @@ func TestGetApplicableCveValue(t *testing.T) { }, }}}}}, }, + { + name: "missing context cve", + entitledForJas: true, + applicabilityScanResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve1"), []string{"applicability"}, []string{"missing_context"}), + }, + cves: []services.Cve{{Id: "testCve1"}}, + expectedResult: jasutils.MissingContext, + expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.MissingContext.String()}}}, + }, { name: "undetermined cve", entitledForJas: true, @@ -467,13 +477,15 @@ func TestGetApplicableCveValue(t *testing.T) { sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve1"), []string{"applicability"}, []string{"applicable"}), sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve2"), []string{"applicability"}, []string{"not_applicable"}), sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve3"), []string{"applicability"}, []string{"not_covered"}), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve4"), []string{"applicability"}, []string{"missing_context"}), }, - cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}, {Id: "testCve3"}}, + cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}, {Id: "testCve3"}, {Id: "testCve4"}}, expectedResult: jasutils.Applicable, expectedCves: []formats.CveRow{ - {Id: "testCve1", Applicability: &formats.Applicability{Status: string(jasutils.Applicable)}}, - {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.NotApplicable)}}, - {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.NotCovered)}}, + {Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.Applicable.String()}}, + {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.NotApplicable.String()}}, + {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.NotCovered.String()}}, + {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.MissingContext.String()}}, }, }, { @@ -504,6 +516,19 @@ func TestGetApplicableCveValue(t *testing.T) { {Id: "testCve2", Applicability: &formats.Applicability{Status: string(jasutils.ApplicabilityUndetermined)}}, }, }, + { + name: "new scan statuses - missing context wins not covered", + entitledForJas: true, + applicabilityScanResults: []*sarif.Run{ + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve1"), []string{"applicability"}, []string{"missing_context"}), + sarifutils.CreateRunWithDummyResultAndRuleProperties(sarifutils.CreateDummyPassingResult("applic_testCve2"), []string{"applicability"}, []string{"not_covered"}), + }, + cves: []services.Cve{{Id: "testCve1"}, {Id: "testCve2"}}, + expectedResult: jasutils.MissingContext, + expectedCves: []formats.CveRow{{Id: "testCve1", Applicability: &formats.Applicability{Status: jasutils.MissingContext.String()}}, + {Id: "testCve2", Applicability: &formats.Applicability{Status: jasutils.NotCovered.String()}}, + }, + }, { name: "undetermined with undetermined reason", entitledForJas: true, diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index ef79188c..a648e1c4 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -639,7 +639,7 @@ func getBaseBinaryDescriptionMarkdown(commandType utils.CommandType, target resu if len(result.Locations) > 0 { location = result.Locations[0] } - return content + getBinaryLocationMarkdownString(commandType, subScanType, location) + return content + getBinaryLocationMarkdownString(commandType, subScanType, result, location) } func getDockerImageTag(commandType utils.CommandType, target results.ScanTarget) string { @@ -656,7 +656,7 @@ func getDockerImageTag(commandType utils.CommandType, target results.ScanTarget) // * Layer: // * Filepath: // * Evidence: -func getBinaryLocationMarkdownString(commandType utils.CommandType, subScanType utils.SubScanType, location *sarif.Location) (content string) { +func getBinaryLocationMarkdownString(commandType utils.CommandType, subScanType utils.SubScanType, result *sarif.Result, location *sarif.Location) (content string) { if location == nil { return "" } @@ -678,6 +678,9 @@ func getBinaryLocationMarkdownString(commandType utils.CommandType, subScanType if snippet := sarifutils.GetLocationSnippetText(location); snippet != "" { content += fmt.Sprintf("\nEvidence: %s", snippet) } + if tokenValidation := results.GetResultPropertyTokenValidation(result); tokenValidation != "" { + content += fmt.Sprintf("\nToken Validation %s", tokenValidation) + } return } diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go index 4d6df490..12e304b6 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go @@ -315,7 +315,8 @@ func PrepareSimpleJsonJasIssues(entitledForJas, pretty bool, jasIssues ...*sarif EndColumn: sarifutils.GetLocationEndColumn(location), Snippet: sarifutils.GetLocationSnippetText(location), }, - CodeFlow: codeFlowToLocationFlow(sarifutils.GetLocationRelatedCodeFlowsFromResult(location, result), run.Invocations, pretty), + Applicability: getJasResultApplicability(result), + CodeFlow: codeFlowToLocationFlow(sarifutils.GetLocationRelatedCodeFlowsFromResult(location, result), run.Invocations, pretty), }, ) return nil @@ -323,6 +324,15 @@ func PrepareSimpleJsonJasIssues(entitledForJas, pretty bool, jasIssues ...*sarif return rows, err } +func getJasResultApplicability(result *sarif.Result) *formats.Applicability { + status := results.GetResultPropertyTokenValidation(result) + statusDescription := results.GetResultPropertyMetadata(result) + if status == "" && statusDescription == "" { + return nil + } + return &formats.Applicability{Status: status, ScannerDescription: statusDescription} +} + func codeFlowToLocationFlow(flows []*sarif.CodeFlow, invocations []*sarif.Invocation, isTable bool) (flowRows [][]formats.Location) { if isTable { // Not displaying in table @@ -606,6 +616,9 @@ func sortSourceCodeRow(rows []formats.SourceCodeRow) { if rows[i].SeverityNumValue != rows[j].SeverityNumValue { return rows[i].SeverityNumValue > rows[j].SeverityNumValue } + if rows[i].Applicability != nil && rows[j].Applicability != nil { + return jasutils.TokenValidationOrder[rows[i].Applicability.Status] < jasutils.TokenValidationOrder[rows[j].Applicability.Status] + } return rows[i].Location.File > rows[j].Location.File }) } diff --git a/utils/results/output/resultwriter.go b/utils/results/output/resultwriter.go index 42f1328f..448f1c79 100644 --- a/utils/results/output/resultwriter.go +++ b/utils/results/output/resultwriter.go @@ -223,7 +223,7 @@ func (rw *ResultsWriter) printTables() (err error) { } } if shouldPrintTable(rw.subScansPreformed, utils.SecretsScan, rw.commandResults.CmdType) { - if err = PrintJasTable(tableContent, rw.commandResults.EntitledForJas, jasutils.Secrets); err != nil { + if err = PrintSecretsTable(tableContent, rw.commandResults.EntitledForJas, rw.commandResults.SecretValidation); err != nil { return } } @@ -306,6 +306,19 @@ func PrintLicensesTable(tables formats.ResultsTables, printExtended bool, cmdTyp return coreutils.PrintTable(tables.LicensesTable, "Licenses", "No licenses were found", printExtended) } +func PrintSecretsTable(tables formats.ResultsTables, entitledForJas, tokenValidationEnabled bool) (err error) { + if !entitledForJas { + return + } + if err = PrintJasTable(tables, entitledForJas, jasutils.Secrets); err != nil { + return + } + if tokenValidationEnabled { + log.Output("This table contains multiple secret types, such as tokens, generic password, ssh keys and more, token validation is only supported on tokens.") + } + return +} + func PrintJasTable(tables formats.ResultsTables, entitledForJas bool, scanType jasutils.JasScanType) error { if !entitledForJas { return nil diff --git a/utils/results/results.go b/utils/results/results.go index ddecca7e..a57ea7b8 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -17,9 +17,10 @@ import ( // SecurityCommandResults is a struct that holds the results of a security scan/audit command. type SecurityCommandResults struct { // General fields describing the command metadata - XrayVersion string `json:"xray_version"` - EntitledForJas bool `json:"jas_entitled"` - CmdType utils.CommandType `json:"command_type"` + XrayVersion string `json:"xray_version"` + EntitledForJas bool `json:"jas_entitled"` + SecretValidation bool `json:"secret_validation,omitempty"` + CmdType utils.CommandType `json:"command_type"` // MultiScanId is a unique identifier that is used to group multiple scans together. MultiScanId string `json:"multi_scan_id,omitempty"` // Results for each target in the command @@ -78,8 +79,8 @@ func (st ScanTarget) String() (str string) { return } -func NewCommandResults(cmdType utils.CommandType, xrayVersion string, entitledForJas bool) *SecurityCommandResults { - return &SecurityCommandResults{CmdType: cmdType, XrayVersion: xrayVersion, EntitledForJas: entitledForJas, targetsMutex: sync.Mutex{}} +func NewCommandResults(cmdType utils.CommandType, xrayVersion string, entitledForJas, secretValidation bool) *SecurityCommandResults { + return &SecurityCommandResults{CmdType: cmdType, XrayVersion: xrayVersion, EntitledForJas: entitledForJas, SecretValidation: secretValidation, targetsMutex: sync.Mutex{}} } func (r *SecurityCommandResults) SetMultiScanId(multiScanId string) *SecurityCommandResults { diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index 988b2cb6..f6b8968d 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -7,6 +7,7 @@ import ( "github.com/jfrog/jfrog-cli-security/utils/formats/sarifutils" "github.com/jfrog/jfrog-cli-security/utils/jasutils" + "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/results/conversion/sarifparser" "github.com/owenrumney/go-sarif/v2/sarif" "github.com/stretchr/testify/assert" @@ -40,17 +41,17 @@ func ValidateCommandSarifOutput(t *testing.T, params ValidationParams) { // Actual content should be a *sarif.Report in the validation params. // If Expected is provided, the validation will check if the Actual content matches the expected results. // If ExactResultsMatch is true, the validation will check exact values and not only the 'equal or grater' counts / existence of expected attributes. (For Integration tests with JFrog API, ExactResultsMatch should be set to false) -func ValidateSarifIssuesCount(t *testing.T, params ValidationParams, results *sarif.Report) { - var vulnerabilities, securityViolations, licenseViolations, applicableResults, undeterminedResults, notCoveredResults, notApplicableResults int +func ValidateSarifIssuesCount(t *testing.T, params ValidationParams, report *sarif.Report) { + var vulnerabilities, securityViolations, licenseViolations, applicableResults, undeterminedResults, notCoveredResults, notApplicableResults, missingContextResults, inactiveResults int - iac := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, IacToolName)...) + iac := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(report, IacToolName)...) vulnerabilities += iac - secrets := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, SecretsToolName)...) + secrets := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(report, SecretsToolName)...) vulnerabilities += secrets - sast := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(results, SastToolName)...) + sast := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(report, SastToolName)...) vulnerabilities += sast - scaRuns := sarifutils.GetRunsByToolName(results, sarifparser.ScaScannerToolName) + scaRuns := sarifutils.GetRunsByToolName(report, sarifparser.ScaScannerToolName) for _, run := range scaRuns { for _, result := range run.Results { // If watch property exists, add to security violations or license violations else add to vulnerabilities @@ -75,33 +76,30 @@ func ValidateSarifIssuesCount(t *testing.T, params ValidationParams, results *sa undeterminedResults++ case jasutils.NotCovered.String(): notCoveredResults++ + case jasutils.MissingContext.String(): + missingContextResults++ } } + if tokenStatus := results.GetResultPropertyTokenValidation(result); tokenStatus == jasutils.Inactive.ToString() { + inactiveResults++ + } } } - if params.ExactResultsMatch { - assert.Equal(t, params.Sast, sast, GetValidationCountErrMsg("sast", "sarif report", true, params.Sast, sast)) - assert.Equal(t, params.Secrets, secrets, GetValidationCountErrMsg("secrets", "sarif report", true, params.Secrets, secrets)) - assert.Equal(t, params.Iac, iac, GetValidationCountErrMsg("Iac", "sarif report", true, params.Iac, iac)) - assert.Equal(t, params.Applicable, applicableResults, "Expected %d applicable results in sarif report, but got %d applicable results.", params.Applicable, applicableResults) - assert.Equal(t, params.Undetermined, undeterminedResults, "Expected %d undetermined results in sarif report, but got %d undetermined results.", params.Undetermined, undeterminedResults) - assert.Equal(t, params.NotCovered, notCoveredResults, "Expected %d not covered results in sarif report, but got %d not covered results.", params.NotCovered, notCoveredResults) - assert.Equal(t, params.NotApplicable, notApplicableResults, "Expected %d not applicable results in sarif report, but got %d not applicable results.", params.NotApplicable, notApplicableResults) - assert.Equal(t, params.SecurityViolations, securityViolations, "Expected %d security violations in sarif report, but got %d security violations.", params.SecurityViolations, securityViolations) - assert.Equal(t, params.LicenseViolations, licenseViolations, "Expected %d license violations in sarif report, but got %d license violations.", params.LicenseViolations, licenseViolations) - assert.Equal(t, params.Vulnerabilities, vulnerabilities, "Expected %d vulnerabilities in sarif report, but got %d vulnerabilities.", params.Vulnerabilities, vulnerabilities) - } else { - assert.GreaterOrEqual(t, sast, params.Sast, "Expected at least %d sast in sarif report, but got %d sast.", params.Sast, sast) - assert.GreaterOrEqual(t, secrets, params.Secrets, "Expected at least %d secrets in sarif report, but got %d secrets.", params.Secrets, secrets) - assert.GreaterOrEqual(t, iac, params.Iac, "Expected at least %d IaC in sarif report, but got %d IaC.", params.Iac, iac) - assert.GreaterOrEqual(t, applicableResults, params.Applicable, "Expected at least %d applicable results in sarif report, but got %d applicable results.", params.Applicable, applicableResults) - assert.GreaterOrEqual(t, undeterminedResults, params.Undetermined, "Expected at least %d undetermined results in sarif report, but got %d undetermined results.", params.Undetermined, undeterminedResults) - assert.GreaterOrEqual(t, notCoveredResults, params.NotCovered, "Expected at least %d not covered results in sarif report, but got %d not covered results.", params.NotCovered, notCoveredResults) - assert.GreaterOrEqual(t, notApplicableResults, params.NotApplicable, "Expected at least %d not applicable results in sarif report, but got %d not applicable results.", params.NotApplicable, notApplicableResults) - assert.GreaterOrEqual(t, securityViolations, params.SecurityViolations, "Expected at least %d security violations in sarif report, but got %d security violations.", params.SecurityViolations, securityViolations) - assert.GreaterOrEqual(t, licenseViolations, params.LicenseViolations, "Expected at least %d license violations in sarif report, but got %d license violations.", params.LicenseViolations, licenseViolations) - } + ValidateContent(t, params.ExactResultsMatch, + CountValidation[int]{Expected: params.Sast, Actual: sast, Msg: GetValidationCountErrMsg("sast", "sarif report", params.ExactResultsMatch, params.Sast, sast)}, + CountValidation[int]{Expected: params.Iac, Actual: iac, Msg: GetValidationCountErrMsg("Iac", "sarif report", params.ExactResultsMatch, params.Iac, iac)}, + CountValidation[int]{Expected: params.Secrets, Actual: secrets, Msg: GetValidationCountErrMsg("secrets", "sarif report", params.ExactResultsMatch, params.Secrets, secrets)}, + CountValidation[int]{Expected: params.Inactive, Actual: inactiveResults, Msg: GetValidationCountErrMsg("inactive secret results", "sarif report", params.ExactResultsMatch, params.Inactive, inactiveResults)}, + CountValidation[int]{Expected: params.Applicable, Actual: applicableResults, Msg: GetValidationCountErrMsg("applicable results", "sarif report", params.ExactResultsMatch, params.Applicable, applicableResults)}, + CountValidation[int]{Expected: params.Undetermined, Actual: undeterminedResults, Msg: GetValidationCountErrMsg("undetermined results", "sarif report", params.ExactResultsMatch, params.Undetermined, undeterminedResults)}, + CountValidation[int]{Expected: params.NotCovered, Actual: notCoveredResults, Msg: GetValidationCountErrMsg("not covered results", "sarif report", params.ExactResultsMatch, params.NotCovered, notCoveredResults)}, + CountValidation[int]{Expected: params.NotApplicable, Actual: notApplicableResults, Msg: GetValidationCountErrMsg("not applicable results", "sarif report", params.ExactResultsMatch, params.NotApplicable, notApplicableResults)}, + CountValidation[int]{Expected: params.MissingContext, Actual: missingContextResults, Msg: GetValidationCountErrMsg("missing context results", "sarif report", params.ExactResultsMatch, params.MissingContext, missingContextResults)}, + CountValidation[int]{Expected: params.SecurityViolations, Actual: securityViolations, Msg: GetValidationCountErrMsg("security violations", "sarif report", params.ExactResultsMatch, params.SecurityViolations, securityViolations)}, + CountValidation[int]{Expected: params.LicenseViolations, Actual: licenseViolations, Msg: GetValidationCountErrMsg("license violations", "sarif report", params.ExactResultsMatch, params.LicenseViolations, licenseViolations)}, + CountValidation[int]{Expected: params.Vulnerabilities, Actual: vulnerabilities, Msg: GetValidationCountErrMsg("vulnerabilities", "sarif report", params.ExactResultsMatch, params.Vulnerabilities, vulnerabilities)}, + ) } func isSecurityIssue(result *sarif.Result) bool { diff --git a/utils/validations/test_validate_sca.go b/utils/validations/test_validate_sca.go index 18b04bff..23591ef8 100644 --- a/utils/validations/test_validate_sca.go +++ b/utils/validations/test_validate_sca.go @@ -38,38 +38,30 @@ func ValidateCommandJsonOutput(t *testing.T, params ValidationParams) { } func ValidateScanResponseIssuesCount(t *testing.T, params ValidationParams, content ...services.ScanResponse) { - var vulnerabilities []services.Vulnerability - var licenses []services.License - var securityViolations []services.Violation - var licenseViolations []services.Violation - var operationalViolations []services.Violation + var vulnerabilities, licenses, securityViolations, licenseViolations, operationalViolations int + for _, result := range content { - vulnerabilities = append(vulnerabilities, result.Vulnerabilities...) - licenses = append(licenses, result.Licenses...) + vulnerabilities += len(result.Vulnerabilities) + licenses += len(result.Licenses) for _, violation := range result.Violations { switch violation.ViolationType { case utils.ViolationTypeSecurity.String(): - securityViolations = append(securityViolations, violation) + securityViolations += 1 case utils.ViolationTypeLicense.String(): - licenseViolations = append(licenseViolations, violation) + licenseViolations += 1 case utils.ViolationTypeOperationalRisk.String(): - operationalViolations = append(operationalViolations, violation) + operationalViolations += 1 } } } - if params.ExactResultsMatch { - assert.Equal(t, params.Vulnerabilities, len(vulnerabilities), fmt.Sprintf("Expected %d vulnerabilities in scan responses, but got %d vulnerabilities.", params.Vulnerabilities, len(vulnerabilities))) - assert.Equal(t, params.Licenses, len(licenses), fmt.Sprintf("Expected %d Licenses in scan responses, but got %d Licenses.", params.Licenses, len(licenses))) - assert.Equal(t, params.SecurityViolations, len(securityViolations), fmt.Sprintf("Expected %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, len(securityViolations))) - assert.Equal(t, params.LicenseViolations, len(licenseViolations), fmt.Sprintf("Expected %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, len(licenseViolations))) - assert.Equal(t, params.OperationalViolations, len(operationalViolations), fmt.Sprintf("Expected %d operational risk violations in scan responses, but got %d operational risk violations.", params.OperationalViolations, len(operationalViolations))) - } else { - assert.GreaterOrEqual(t, len(vulnerabilities), params.Vulnerabilities, fmt.Sprintf("Expected at least %d vulnerabilities in scan responses, but got %d vulnerabilities.", params.Vulnerabilities, len(vulnerabilities))) - assert.GreaterOrEqual(t, len(licenses), params.Licenses, fmt.Sprintf("Expected at least %d Licenses in scan responses, but got %d Licenses.", params.Licenses, len(licenses))) - assert.GreaterOrEqual(t, len(securityViolations), params.SecurityViolations, fmt.Sprintf("Expected at least %d security violations in scan responses, but got %d security violations.", params.LicenseViolations, len(securityViolations))) - assert.GreaterOrEqual(t, len(licenseViolations), params.LicenseViolations, fmt.Sprintf("Expected at least %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, len(licenseViolations))) - assert.GreaterOrEqual(t, len(operationalViolations), params.OperationalViolations, fmt.Sprintf("Expected at least %d operational risk violations in scan responses, but got %d operational risk violations.", params.OperationalViolations, len(operationalViolations))) - } + + ValidateContent(t, params.ExactResultsMatch, + CountValidation[int]{Expected: params.Vulnerabilities, Actual: vulnerabilities, Msg: GetValidationCountErrMsg("vulnerabilities", "scan responses", params.ExactResultsMatch, params.Vulnerabilities, vulnerabilities)}, + CountValidation[int]{Expected: params.Licenses, Actual: licenses, Msg: GetValidationCountErrMsg("licenses", "scan responses", params.ExactResultsMatch, params.Licenses, licenses)}, + CountValidation[int]{Expected: params.SecurityViolations, Actual: securityViolations, Msg: GetValidationCountErrMsg("security violations", "scan responses", params.ExactResultsMatch, params.SecurityViolations, securityViolations)}, + CountValidation[int]{Expected: params.LicenseViolations, Actual: licenseViolations, Msg: GetValidationCountErrMsg("license violations", "scan responses", params.ExactResultsMatch, params.LicenseViolations, licenseViolations)}, + CountValidation[int]{Expected: params.OperationalViolations, Actual: operationalViolations, Msg: GetValidationCountErrMsg("operational risk violations", "scan responses", params.ExactResultsMatch, params.OperationalViolations, operationalViolations)}, + ) } func ValidateScanResponses(t *testing.T, exactMatch bool, expected, actual []services.ScanResponse) { diff --git a/utils/validations/test_validate_simple_json.go b/utils/validations/test_validate_simple_json.go index 4507cf3a..16b42cf1 100644 --- a/utils/validations/test_validate_simple_json.go +++ b/utils/validations/test_validate_simple_json.go @@ -44,51 +44,47 @@ func ValidateCommandSimpleJsonOutput(t *testing.T, params ValidationParams) { // If Expected is provided, the validation will check if the Actual content matches the expected results. // If ExactResultsMatch is true, the validation will check exact values and not only the 'equal or grater' counts / existence of expected attributes. (For Integration tests with JFrog API, ExactResultsMatch should be set to false) func ValidateSimpleJsonIssuesCount(t *testing.T, params ValidationParams, results formats.SimpleJsonResults) { - var applicableResults, undeterminedResults, notCoveredResults, notApplicableResults int + var applicableResults, undeterminedResults, notCoveredResults, notApplicableResults, missingContextResults, inactiveResults int for _, vuln := range results.Vulnerabilities { switch vuln.Applicable { - case string(jasutils.NotApplicable): + case jasutils.NotApplicable.String(): notApplicableResults++ - case string(jasutils.Applicable): + case jasutils.Applicable.String(): applicableResults++ - case string(jasutils.NotCovered): + case jasutils.NotCovered.String(): notCoveredResults++ - case string(jasutils.ApplicabilityUndetermined): + case jasutils.ApplicabilityUndetermined.String(): undeterminedResults++ + case jasutils.MissingContext.String(): + missingContextResults++ } } - - if params.ExactResultsMatch { - assert.Equal(t, params.Sast, len(results.Sast), "Expected %d sast in scan responses, but got %d sast.", params.Sast, len(results.Sast)) - assert.Equal(t, params.Secrets, len(results.Secrets), "Expected %d secrets in scan responses, but got %d secrets.", params.Secrets, len(results.Secrets)) - assert.Equal(t, params.Iac, len(results.Iacs), "Expected %d IaC in scan responses, but got %d IaC.", params.Iac, len(results.Iacs)) - - assert.Equal(t, params.Applicable, applicableResults, "Expected %d applicable vulnerabilities in scan responses, but got %d applicable vulnerabilities.", params.Applicable, applicableResults) - assert.Equal(t, params.Undetermined, undeterminedResults, "Expected %d undetermined vulnerabilities in scan responses, but got %d undetermined vulnerabilities.", params.Undetermined, undeterminedResults) - assert.Equal(t, params.NotCovered, notCoveredResults, "Expected %d not covered vulnerabilities in scan responses, but got %d not covered vulnerabilities.", params.NotCovered, notCoveredResults) - assert.Equal(t, params.NotApplicable, notApplicableResults, "Expected %d not applicable vulnerabilities in scan responses, but got %d not applicable vulnerabilities.", params.NotApplicable, notApplicableResults) - - assert.Equal(t, params.SecurityViolations, len(results.SecurityViolations), "Expected %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, len(results.SecurityViolations)) - assert.Equal(t, params.LicenseViolations, len(results.LicensesViolations), "Expected %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, len(results.LicensesViolations)) - assert.Equal(t, params.OperationalViolations, len(results.OperationalRiskViolations), "Expected %d operational risk violations in scan responses, but got %d operational risk violations.", params.OperationalViolations, len(results.OperationalRiskViolations)) - - assert.Equal(t, params.Licenses, len(results.Licenses), "Expected %d Licenses in scan responses, but got %d Licenses.", params.Licenses, len(results.Licenses)) - return + for _, result := range results.Secrets { + if result.Applicability != nil { + if result.Applicability.Status == jasutils.Inactive.ToString() { + inactiveResults += 1 + } + } } - assert.GreaterOrEqual(t, len(results.Sast), params.Sast, "Expected at least %d sast in scan responses, but got %d sast.", params.Sast, len(results.Sast)) - assert.GreaterOrEqual(t, len(results.Secrets), params.Secrets, "Expected at least %d secrets in scan responses, but got %d secrets.", params.Secrets, len(results.Secrets)) - assert.GreaterOrEqual(t, len(results.Iacs), params.Iac, "Expected at least %d IaC in scan responses, but got %d IaC.", params.Iac, len(results.Iacs)) - assert.GreaterOrEqual(t, applicableResults, params.Applicable, "Expected at least %d applicable vulnerabilities in scan responses, but got %d applicable vulnerabilities.", params.Applicable, applicableResults) - assert.GreaterOrEqual(t, undeterminedResults, params.Undetermined, "Expected at least %d undetermined vulnerabilities in scan responses, but got %d undetermined vulnerabilities.", params.Undetermined, undeterminedResults) - assert.GreaterOrEqual(t, notCoveredResults, params.NotCovered, "Expected at least %d not covered vulnerabilities in scan responses, but got %d not covered vulnerabilities.", params.NotCovered, notCoveredResults) - assert.GreaterOrEqual(t, notApplicableResults, params.NotApplicable, "Expected at least %d not applicable vulnerabilities in scan responses, but got %d not applicable vulnerabilities.", params.NotApplicable, notApplicableResults) + ValidateContent(t, params.ExactResultsMatch, + CountValidation[int]{Expected: params.Vulnerabilities, Actual: len(results.Vulnerabilities), Msg: GetValidationCountErrMsg("vulnerabilities", "simple-json", params.ExactResultsMatch, params.Vulnerabilities, len(results.Vulnerabilities))}, + CountValidation[int]{Expected: params.Sast, Actual: len(results.Sast), Msg: GetValidationCountErrMsg("sast", "simple-json", params.ExactResultsMatch, params.Sast, len(results.Sast))}, + CountValidation[int]{Expected: params.Iac, Actual: len(results.Iacs), Msg: GetValidationCountErrMsg("IaC", "simple-json", params.ExactResultsMatch, params.Iac, len(results.Iacs))}, + CountValidation[int]{Expected: params.Secrets, Actual: len(results.Secrets), Msg: GetValidationCountErrMsg("secrets", "simple-json", params.ExactResultsMatch, params.Secrets, len(results.Secrets))}, + CountValidation[int]{Expected: params.Inactive, Actual: inactiveResults, Msg: GetValidationCountErrMsg("inactive secrets", "simple-json", params.ExactResultsMatch, params.Inactive, inactiveResults)}, - assert.GreaterOrEqual(t, len(results.SecurityViolations), params.SecurityViolations, "Expected at least %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, len(results.SecurityViolations)) - assert.GreaterOrEqual(t, len(results.LicensesViolations), params.LicenseViolations, "Expected at least %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, len(results.LicensesViolations)) - assert.GreaterOrEqual(t, len(results.OperationalRiskViolations), params.OperationalViolations, "Expected at least %d operational risk violations in scan responses, but got %d operational risk violations.", params.OperationalViolations, len(results.OperationalRiskViolations)) + CountValidation[int]{Expected: params.Applicable, Actual: applicableResults, Msg: GetValidationCountErrMsg("applicable vulnerabilities", "simple-json", params.ExactResultsMatch, params.Applicable, applicableResults)}, + CountValidation[int]{Expected: params.Undetermined, Actual: undeterminedResults, Msg: GetValidationCountErrMsg("undetermined vulnerabilities", "simple-json", params.ExactResultsMatch, params.Undetermined, undeterminedResults)}, + CountValidation[int]{Expected: params.NotCovered, Actual: notCoveredResults, Msg: GetValidationCountErrMsg("not covered vulnerabilities", "simple-json", params.ExactResultsMatch, params.NotCovered, notCoveredResults)}, + CountValidation[int]{Expected: params.NotApplicable, Actual: notApplicableResults, Msg: GetValidationCountErrMsg("not applicable vulnerabilities", "simple-json", params.ExactResultsMatch, params.NotApplicable, notApplicableResults)}, + CountValidation[int]{Expected: params.MissingContext, Actual: missingContextResults, Msg: GetValidationCountErrMsg("missing context vulnerabilities", "simple-json", params.ExactResultsMatch, params.MissingContext, missingContextResults)}, - assert.GreaterOrEqual(t, len(results.Licenses), params.Licenses, "Expected at least %d Licenses in scan responses, but got %d Licenses.", params.Licenses, len(results.Licenses)) + CountValidation[int]{Expected: params.SecurityViolations, Actual: len(results.SecurityViolations), Msg: GetValidationCountErrMsg("security violations", "simple-json", params.ExactResultsMatch, params.SecurityViolations, len(results.SecurityViolations))}, + CountValidation[int]{Expected: params.LicenseViolations, Actual: len(results.LicensesViolations), Msg: GetValidationCountErrMsg("license violations", "simple-json", params.ExactResultsMatch, params.LicenseViolations, len(results.LicensesViolations))}, + CountValidation[int]{Expected: params.OperationalViolations, Actual: len(results.OperationalRiskViolations), Msg: GetValidationCountErrMsg("operational risk violations", "simple-json", params.ExactResultsMatch, params.OperationalViolations, len(results.OperationalRiskViolations))}, + CountValidation[int]{Expected: params.Licenses, Actual: len(results.Licenses), Msg: GetValidationCountErrMsg("Licenses", "simple-json", params.ExactResultsMatch, params.Licenses, len(results.Licenses))}, + ) } func ValidateSimpleJsonResults(t *testing.T, exactMatch bool, expected, actual formats.SimpleJsonResults) { diff --git a/utils/validations/test_validate_summary.go b/utils/validations/test_validate_summary.go index ea40fa6f..5eedf12e 100644 --- a/utils/validations/test_validate_summary.go +++ b/utils/validations/test_validate_summary.go @@ -20,7 +20,7 @@ func ValidateCommandSummaryOutput(t *testing.T, params ValidationParams) { } func ValidateSummaryIssuesCount(t *testing.T, params ValidationParams, results formats.ResultsSummary) { - var vulnerabilities, securityViolations, licenseViolations, opRiskViolations, applicableResults, undeterminedResults, notCoveredResults, notApplicableResults, sast, iac, secrets int + var vulnerabilities, securityViolations, licenseViolations, opRiskViolations, applicableResults, undeterminedResults, notCoveredResults, notApplicableResults, missingContextResults, sast, iac, secrets int vulnerabilities = results.GetTotalVulnerabilities() @@ -46,42 +46,27 @@ func ValidateSummaryIssuesCount(t *testing.T, params ValidationParams, results f notCoveredResults += count case jasutils.NotApplicable.String(): notApplicableResults += count + case jasutils.MissingContext.String(): + missingContextResults += count } } } } } } - // validate the counts - if params.ExactResultsMatch { - assert.Equal(t, params.Vulnerabilities, vulnerabilities, "Expected %d vulnerabilities in scan responses, but got %d vulnerabilities.", params.Vulnerabilities, vulnerabilities) - assert.Equal(t, params.Sast, sast, "Expected %d sast in scan responses, but got %d sast.", params.Sast, sast) - assert.Equal(t, params.Secrets, secrets, "Expected %d secrets in scan responses, but got %d secrets.", params.Secrets, secrets) - assert.Equal(t, params.Iac, iac, "Expected %d IaC in scan responses, but got %d IaC.", params.Iac, iac) - - assert.Equal(t, params.Applicable, applicableResults, "Expected %d applicable vulnerabilities in scan responses, but got %d applicable vulnerabilities.", params.Applicable, applicableResults) - assert.Equal(t, params.Undetermined, undeterminedResults, "Expected %d undetermined vulnerabilities in scan responses, but got %d undetermined vulnerabilities.", params.Undetermined, undeterminedResults) - assert.Equal(t, params.NotCovered, notCoveredResults, "Expected %d not covered vulnerabilities in scan responses, but got %d not covered vulnerabilities.", params.NotCovered, notCoveredResults) - assert.Equal(t, params.NotApplicable, notApplicableResults, "Expected %d not applicable vulnerabilities in scan responses, but got %d not applicable vulnerabilities.", params.NotApplicable, notApplicableResults) - - assert.Equal(t, params.SecurityViolations, securityViolations, "Expected %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, securityViolations) - assert.Equal(t, params.LicenseViolations, licenseViolations, "Expected %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, licenseViolations) - assert.Equal(t, params.OperationalViolations, opRiskViolations, "Expected %d operational risk violations in scan responses, but got %d operational risk violations.", params.OperationalViolations, opRiskViolations) - return - } - assert.GreaterOrEqual(t, vulnerabilities, params.Vulnerabilities, "Expected at least %d vulnerabilities in scan responses, but got %d vulnerabilities.", params.Vulnerabilities, vulnerabilities) - - assert.GreaterOrEqual(t, sast, params.Sast, "Expected at least %d sast in scan responses, but got %d sast.", params.Sast, sast) - assert.GreaterOrEqual(t, secrets, params.Secrets, "Expected at least %d secrets in scan responses, but got %d secrets.", params.Secrets, secrets) - assert.GreaterOrEqual(t, iac, params.Iac, "Expected at least %d IaC in scan responses, but got %d IaC.", params.Iac, iac) - - assert.GreaterOrEqual(t, applicableResults, params.Applicable, "Expected at least %d applicable vulnerabilities in scan responses, but got %d applicable vulnerabilities.", params.Applicable, applicableResults) - assert.GreaterOrEqual(t, undeterminedResults, params.Undetermined, "Expected at least %d undetermined vulnerabilities in scan responses, but got %d undetermined vulnerabilities.", params.Undetermined, undeterminedResults) - assert.GreaterOrEqual(t, notCoveredResults, params.NotCovered, "Expected at least %d not covered vulnerabilities in scan responses, but got %d not covered vulnerabilities.", params.NotCovered, notCoveredResults) - assert.GreaterOrEqual(t, notApplicableResults, params.NotApplicable, "Expected at least %d not applicable vulnerabilities in scan responses, but got %d not applicable vulnerabilities.", params.NotApplicable, notApplicableResults) - - assert.GreaterOrEqual(t, securityViolations, params.SecurityViolations, "Expected at least %d security violations in scan responses, but got %d security violations.", params.SecurityViolations, securityViolations) - assert.GreaterOrEqual(t, licenseViolations, params.LicenseViolations, "Expected at least %d license violations in scan responses, but got %d license violations.", params.LicenseViolations, licenseViolations) - assert.GreaterOrEqual(t, securityViolations, params.OperationalViolations, "Expected at least %d operational risk violations in scan responses, but got %d operational risk violations.", params.OperationalViolations, opRiskViolations) + ValidateContent(t, params.ExactResultsMatch, + CountValidation[int]{Expected: params.Vulnerabilities, Actual: vulnerabilities, Msg: GetValidationCountErrMsg("vulnerabilities", "summary", params.ExactResultsMatch, params.Vulnerabilities, vulnerabilities)}, + CountValidation[int]{Expected: params.Sast, Actual: sast, Msg: GetValidationCountErrMsg("sast", "summary", params.ExactResultsMatch, params.Sast, sast)}, + CountValidation[int]{Expected: params.Secrets, Actual: secrets, Msg: GetValidationCountErrMsg("secrets", "summary", params.ExactResultsMatch, params.Secrets, secrets)}, + CountValidation[int]{Expected: params.Iac, Actual: iac, Msg: GetValidationCountErrMsg("IaC", "summary", params.ExactResultsMatch, params.Iac, iac)}, + CountValidation[int]{Expected: params.Applicable, Actual: applicableResults, Msg: GetValidationCountErrMsg("applicable vulnerabilities", "summary", params.ExactResultsMatch, params.Applicable, applicableResults)}, + CountValidation[int]{Expected: params.Undetermined, Actual: undeterminedResults, Msg: GetValidationCountErrMsg("undetermined vulnerabilities", "summary", params.ExactResultsMatch, params.Undetermined, undeterminedResults)}, + CountValidation[int]{Expected: params.NotCovered, Actual: notCoveredResults, Msg: GetValidationCountErrMsg("not covered vulnerabilities", "summary", params.ExactResultsMatch, params.NotCovered, notCoveredResults)}, + CountValidation[int]{Expected: params.NotApplicable, Actual: notApplicableResults, Msg: GetValidationCountErrMsg("not applicable vulnerabilities", "summary", params.ExactResultsMatch, params.NotApplicable, notApplicableResults)}, + CountValidation[int]{Expected: params.MissingContext, Actual: missingContextResults, Msg: GetValidationCountErrMsg("missing context vulnerabilities", "summary", params.ExactResultsMatch, params.MissingContext, missingContextResults)}, + CountValidation[int]{Expected: params.SecurityViolations, Actual: securityViolations, Msg: GetValidationCountErrMsg("security violations", "summary", params.ExactResultsMatch, params.SecurityViolations, securityViolations)}, + CountValidation[int]{Expected: params.LicenseViolations, Actual: licenseViolations, Msg: GetValidationCountErrMsg("license violations", "summary", params.ExactResultsMatch, params.LicenseViolations, licenseViolations)}, + CountValidation[int]{Expected: params.OperationalViolations, Actual: opRiskViolations, Msg: GetValidationCountErrMsg("operational risk violations", "summary", params.ExactResultsMatch, params.OperationalViolations, opRiskViolations)}, + ) } diff --git a/utils/validations/test_validation.go b/utils/validations/test_validation.go index 04dafe74..21d86bfd 100644 --- a/utils/validations/test_validation.go +++ b/utils/validations/test_validation.go @@ -38,6 +38,8 @@ type ValidationParams struct { Undetermined int NotCovered int NotApplicable int + MissingContext int + Inactive int Sast int Iac int Secrets int @@ -77,6 +79,29 @@ func (sv StringValidation) ErrMsgs(_ *testing.T) []string { return []string{sv.Msg} } +// CountValidation validates the content of the given numbers. +// Not ExactMatch: The actual content must be greater or equal to the expected content. +type CountValidation[T any] struct { + Expected int + Actual int + Msg string +} + +func (cv CountValidation[T]) Validate(t *testing.T, exactMatch bool) bool { + return validateNumberCount(t, cv.Expected, cv.Actual, exactMatch, cv.ErrMsgs(t)) +} + +func validateNumberCount(t *testing.T, expected, actual interface{}, actualValue bool, msgAndArgs ...interface{}) bool { + if actualValue { + return assert.Equal(t, expected, actual, msgAndArgs...) + } + return assert.GreaterOrEqual(t, actual, expected, msgAndArgs...) +} + +func (cv CountValidation[T]) ErrMsgs(_ *testing.T) []string { + return []string{cv.Msg} +} + // NumberValidation validates the content of the given numbers. // Not ExactMatch: The actual content must not be zero if the expected content is not zero. type NumberValidation[T any] struct { diff --git a/utils/xsc/analyticsmetrics_test.go b/utils/xsc/analyticsmetrics_test.go index aca3198f..1af8a864 100644 --- a/utils/xsc/analyticsmetrics_test.go +++ b/utils/xsc/analyticsmetrics_test.go @@ -109,7 +109,7 @@ func TestAnalyticsMetricsService_createAuditResultsFromXscAnalyticsBasicGeneralE func getDummyContentForGeneralEvent(withJas, withErr bool) *results.SecurityCommandResults { vulnerabilities := []services.Vulnerability{{IssueId: "XRAY-ID", Severity: "medium", Cves: []services.Cve{{Id: "CVE-123"}}, Components: map[string]services.Component{"issueId_2_direct_dependency": {}}}} - cmdResults := results.NewCommandResults(utils.SourceCode, "", true) + cmdResults := results.NewCommandResults(utils.SourceCode, "", true, true) scanResults := cmdResults.NewScanResults(results.ScanTarget{Target: "target"}) scanResults.NewScaScanResults(services.ScanResponse{Vulnerabilities: vulnerabilities}) From a3372e1f56ebe87b0eeabab2c68321ad5218d2d6 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 24 Sep 2024 11:30:02 +0300 Subject: [PATCH 62/82] done fix merge conflicts --- commands/audit/audit_test.go | 2 +- commands/enrich/enrich.go | 2 +- commands/scan/buildscan.go | 2 +- commands/scan/scan.go | 15 +++--- jas/common_test.go | 90 +++++++++++++++++++----------------- jas/runner/jasrunner_test.go | 8 ++-- 6 files changed, 63 insertions(+), 56 deletions(-) diff --git a/commands/audit/audit_test.go b/commands/audit/audit_test.go index 23d20b40..2fa1df1e 100644 --- a/commands/audit/audit_test.go +++ b/commands/audit/audit_test.go @@ -169,7 +169,7 @@ func TestDetectScansToPreform(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - results := results.NewCommandResults(utils.SourceCode, "", true) + results := results.NewCommandResults(utils.SourceCode, "", true, true) detectScanTargets(results, test.params()) if assert.Len(t, results.Targets, len(test.expected)) { for i := range results.Targets { diff --git a/commands/enrich/enrich.go b/commands/enrich/enrich.go index 89516b87..ec3c748e 100644 --- a/commands/enrich/enrich.go +++ b/commands/enrich/enrich.go @@ -156,7 +156,7 @@ func (enrichCmd *EnrichCommand) Run() (err error) { log.Info("JFrog Xray version is:", xrayVersion) - scanResults := results.NewCommandResults(utils.SBOM, xrayVersion, false) + scanResults := results.NewCommandResults(utils.SBOM, xrayVersion, false, false) fileProducerConsumer := parallel.NewRunner(enrichCmd.threads, 20000, false) indexedFileProducerConsumer := parallel.NewRunner(enrichCmd.threads, 20000, false) diff --git a/commands/scan/buildscan.go b/commands/scan/buildscan.go index 2b45a9c0..30f52998 100644 --- a/commands/scan/buildscan.go +++ b/commands/scan/buildscan.go @@ -145,7 +145,7 @@ func (bsc *BuildScanCommand) runBuildScanAndPrintResults(xrayManager *xray.XrayS log.Info("The scan data is available at: " + buildScanResults.MoreDetailsUrl) isFailBuildResponse = buildScanResults.FailBuild - cmdResults := results.NewCommandResults(utils.Build, xrayVersion, false) + cmdResults := results.NewCommandResults(utils.Build, xrayVersion, false, false) scanResults := cmdResults.NewScanResults(results.ScanTarget{Name: fmt.Sprintf("%s (%s)", params.BuildName, params.BuildNumber)}) scanResults.NewScaScanResults(services.ScanResponse{ Violations: buildScanResults.Violations, diff --git a/commands/scan/scan.go b/commands/scan/scan.go index fff53fb1..2b84622d 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -238,12 +238,15 @@ func (scanCmd *ScanCommand) RunAndRecordResults(cmdType utils.CommandType, recor return err } - cmdResults := results.NewCommandResults(cmdType, xrayVersion, entitledForJas && scanCmd.commandSupportsJAS) + cmdResults := results.NewCommandResults( + cmdType, + xrayVersion, + entitledForJas && scanCmd.commandSupportsJAS, + jas.CheckForSecretValidation(xrayManager, xrayVersion, scanCmd.validateSecrets), + ) if scanCmd.analyticsMetricsService != nil { cmdResults.SetMultiScanId(scanCmd.analyticsMetricsService.GetMsi()) } - - scanResults.ExtendedScanResults.SecretValidation = jas.CheckForSecretValidation(xrayManager, xrayVersion, scanCmd.validateSecrets) errGroup := new(errgroup.Group) if cmdResults.EntitledForJas { // Download (if needed) the analyzer manager in a background routine. @@ -442,7 +445,7 @@ func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, cmdResults return } // Run Jas scans - scanner, err := getJasScanner(filePath, scanCmd.serverDetails, targetResults) + scanner, err := getJasScanner(scanCmd.serverDetails, targetResults, cmdResults.SecretValidation) if err != nil { return err } @@ -474,8 +477,8 @@ func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, cmdResults } } -func getJasScanner(_ string, serverDetails *config.ServerDetails, targetResults *results.TargetResults) (*jas.JasScanner, error) { - scanner, err := jas.CreateJasScanner(&jas.JasScanner{}, serverDetails, jas.GetAnalyzerManagerXscEnvVars("", targetResults.GetTechnologies()...)) +func getJasScanner(serverDetails *config.ServerDetails, targetResults *results.TargetResults, secretValidation bool) (*jas.JasScanner, error) { + scanner, err := jas.CreateJasScanner(&jas.JasScanner{}, serverDetails, secretValidation, jas.GetAnalyzerManagerXscEnvVars("", targetResults.GetTechnologies()...)) if err != nil { log.Error(fmt.Sprintf("failed to create jas scanner: %s", err.Error())) targetResults.AddError(err) diff --git a/jas/common_test.go b/jas/common_test.go index a54ebc0e..f499db8e 100644 --- a/jas/common_test.go +++ b/jas/common_test.go @@ -114,11 +114,13 @@ func TestConvertToFilesExcludePatterns(t *testing.T) { } } -func TestGetAnalyzerManagerEnvVariables(t *testing.T) { +func TestGetJasEnvVars(t *testing.T) { tests := []struct { - name string - serverDetails *config.ServerDetails - expectedOutput map[string]string + name string + serverDetails *config.ServerDetails + validateSecrets bool + extraEnvVars map[string]string + expectedOutput map[string]string }{ { name: "Valid server details", @@ -129,16 +131,36 @@ func TestGetAnalyzerManagerEnvVariables(t *testing.T) { AccessToken: "token", }, expectedOutput: map[string]string{ - jfPlatformUrlEnvVariable: "url", - jfUserEnvVariable: "user", - jfPasswordEnvVariable: "password", - jfTokenEnvVariable: "token", + jfPlatformUrlEnvVariable: "url", + jfUserEnvVariable: "user", + jfPasswordEnvVariable: "password", + jfTokenEnvVariable: "token", + JfSecretValidationEnvVariable: "false", + }, + }, + { + name: "With validate secrets", + serverDetails: &config.ServerDetails{ + Url: "url", + User: "user", + Password: "password", + AccessToken: "token", + }, + extraEnvVars: map[string]string{"test": "testValue"}, + validateSecrets: true, + expectedOutput: map[string]string{ + jfPlatformUrlEnvVariable: "url", + jfUserEnvVariable: "user", + jfPasswordEnvVariable: "password", + jfTokenEnvVariable: "token", + JfSecretValidationEnvVariable: "true", + "test": "testValue", }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - envVars, err := GetAnalyzerManagerEnvVariables(test.serverDetails) + envVars, err := getJasEnvVars(test.serverDetails, test.validateSecrets, test.extraEnvVars) assert.NoError(t, err) for expectedKey, expectedValue := range test.expectedOutput { assert.Equal(t, expectedValue, envVars[expectedKey]) @@ -149,55 +171,37 @@ func TestGetAnalyzerManagerEnvVariables(t *testing.T) { func TestGetAnalyzerManagerXscEnvVars(t *testing.T) { tests := []struct { - name string - msi string - validateSecrets bool - technologies []techutils.Technology - expectedOutput map[string]string + name string + msi string + technologies []techutils.Technology + expectedOutput map[string]string }{ { name: "One valid technology", msi: "msi", technologies: []techutils.Technology{techutils.Maven}, expectedOutput: map[string]string{ - JfPackageManagerEnvVariable: string(techutils.Maven), - JfLanguageEnvVariable: string(techutils.Java), - JfSecretValidationEnvVariable: "false", - utils.JfMsiEnvVariable: "msi", + JfPackageManagerEnvVariable: string(techutils.Maven), + JfLanguageEnvVariable: string(techutils.Java), + utils.JfMsiEnvVariable: "msi", }, }, { - name: "Multiple technologies", - msi: "msi", - technologies: []techutils.Technology{techutils.Maven, techutils.Npm}, - expectedOutput: map[string]string{ - JfSecretValidationEnvVariable: "false", - utils.JfMsiEnvVariable: "msi", - }, + name: "Multiple technologies", + msi: "msi", + technologies: []techutils.Technology{techutils.Maven, techutils.Npm}, + expectedOutput: map[string]string{utils.JfMsiEnvVariable: "msi"}, }, { - name: "Zero technologies", - msi: "msi", - technologies: []techutils.Technology{}, - expectedOutput: map[string]string{ - utils.JfMsiEnvVariable: "msi", - JfSecretValidationEnvVariable: "false", - }, - }, - { - name: "with validate secrets", - msi: "msi", - validateSecrets: true, - technologies: []techutils.Technology{}, - expectedOutput: map[string]string{ - utils.JfMsiEnvVariable: "msi", - JfSecretValidationEnvVariable: "true", - }, + name: "Zero technologies", + msi: "msi", + technologies: []techutils.Technology{}, + expectedOutput: map[string]string{utils.JfMsiEnvVariable: "msi"}, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - assert.Equal(t, test.expectedOutput, GetAnalyzerManagerXscEnvVars(test.msi, test.validateSecrets, test.technologies...)) + assert.Equal(t, test.expectedOutput, GetAnalyzerManagerXscEnvVars(test.msi, test.technologies...)) }) } } diff --git a/jas/runner/jasrunner_test.go b/jas/runner/jasrunner_test.go index 1802404e..326ed317 100644 --- a/jas/runner/jasrunner_test.go +++ b/jas/runner/jasrunner_test.go @@ -28,17 +28,17 @@ func TestGetExtendedScanResults_AnalyzerManagerDoesntExist(t *testing.T) { assert.NoError(t, os.Unsetenv(coreutils.HomeDir)) }() scanner := &jas.JasScanner{} - _, err = jas.CreateJasScanner(scanner, nil, &jas.FakeServerDetails, jas.GetAnalyzerManagerXscEnvVars("")) + _, err = jas.CreateJasScanner(scanner, &jas.FakeServerDetails, false, jas.GetAnalyzerManagerXscEnvVars("")) assert.Error(t, err) assert.ErrorContains(t, err, "unable to locate the analyzer manager package. Advanced security scans cannot be performed without this package") } func TestGetExtendedScanResults_ServerNotValid(t *testing.T) { securityParallelRunnerForTest := utils.CreateSecurityParallelRunner(cliutils.Threads) - targetResults := results.NewCommandResults(utils.SourceCode, "", true).NewScanResults(results.ScanTarget{Target: "target", Technology: techutils.Pip}) + targetResults := results.NewCommandResults(utils.SourceCode, "", true, true).NewScanResults(results.ScanTarget{Target: "target", Technology: techutils.Pip}) scanner := &jas.JasScanner{} - jasScanner, err := jas.CreateJasScanner(scanner, nil, &jas.FakeServerDetails, jas.GetAnalyzerManagerXscEnvVars("", scanResults.GetScaScannedTechnologies()...)) + jasScanner, err := jas.CreateJasScanner(scanner, &jas.FakeServerDetails, true, jas.GetAnalyzerManagerXscEnvVars("", targetResults.GetTechnologies()...)) assert.NoError(t, err) targetResults.NewScaScanResults(jas.FakeBasicXrayResults[0]) @@ -62,7 +62,7 @@ func TestGetExtendedScanResults_AnalyzerManagerReturnsError(t *testing.T) { jfrogAppsConfigForTest, _ := jas.CreateJFrogAppsConfig(nil) scanner := &jas.JasScanner{} - scanner, _ = jas.CreateJasScanner(scanner, nil, &jas.FakeServerDetails, jas.GetAnalyzerManagerXscEnvVars("")) + scanner, _ = jas.CreateJasScanner(scanner, &jas.FakeServerDetails, false, jas.GetAnalyzerManagerXscEnvVars("")) _, err := applicability.RunApplicabilityScan(jas.FakeBasicXrayResults, []string{"issueId_2_direct_dependency", "issueId_1_direct_dependency"}, scanner, false, applicability.ApplicabilityScannerType, jfrogAppsConfigForTest.Modules[0], 0) From 16b939293624030d36ae1ae423b135e332fe16d7 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 24 Sep 2024 13:13:28 +0300 Subject: [PATCH 63/82] continue fix tests --- jobTestData/debug/sarif.json | 778 +++++++++ jobTestData/debug/simple.json | 826 ++++++++++ .../output/dockerscan/docker_sarif.json | 1416 ++++++++-------- .../output/dockerscan/docker_simple_json.json | 1450 ++++++++--------- utils/formats/sarifutils/test_sarifutils.go | 1 + utils/results/conversion/convertor_test.go | 8 +- .../simplejsonparser/simplejsonparser_test.go | 22 +- 7 files changed, 3051 insertions(+), 1450 deletions(-) create mode 100644 jobTestData/debug/sarif.json create mode 100644 jobTestData/debug/simple.json diff --git a/jobTestData/debug/sarif.json b/jobTestData/debug/sarif.json new file mode 100644 index 00000000..b8df3082 --- /dev/null +++ b/jobTestData/debug/sarif.json @@ -0,0 +1,778 @@ +{ + "version": "2.1.0", + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "runs": [ + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Binary Secrets Scanner", + "rules": [ + { + "id": "REQ.SECRET.GENERIC.TEXT", + "name": "REQ.SECRET.GENERIC.TEXT", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.TEXT" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.GENERIC.CODE", + "name": "REQ.SECRET.GENERIC.CODE", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.CODE" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + }, + { + "id": "REQ.SECRET.KEYS", + "name": "REQ.SECRET.KEYS", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.KEYS" + }, + "fullDescription": { + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + "help": { + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + }, + { + "id": "REQ.CRED.PUBLIC-ONLY", + "name": "REQ.CRED.PUBLIC-ONLY", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.CRED.PUBLIC-ONLY" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "help": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "undetermined", + "conclusion": "private" + } + }, + { + "id": "REQ.SECRET.GENERIC.URL", + "name": "REQ.SECRET.GENERIC.URL", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.URL" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/user/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210780-681556384/Secrets_1726210839/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210535-1985298017/image.tar" + } + } + ], + "results": [ + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "REQ.SECRET.GENERIC.CODE", + "message": { + "text": "Hardcoded secrets were found", + "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: usr/src/app/server/index.js\nEvidence: tok************" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "usr/src/app/server/index.js" + }, + "region": { + "startLine": 5, + "startColumn": 7, + "endLine": 5, + "endColumn": 57, + "snippet": { + "text": "tok************" + } + } + }, + "logicalLocations": [ + { + "name": "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "00436fac1d19ea36302f14e892926efb" + } + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found", + "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: usr/src/app/server/index.js\nEvidence: eyJ************" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "usr/src/app/server/index.js" + }, + "region": { + "startLine": 6, + "startColumn": 14, + "endLine": 6, + "endColumn": 24, + "snippet": { + "text": "eyJ************" + } + } + }, + "logicalLocations": [ + { + "name": "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "2550dbdb124696ae8fcc5cfd6f2b65b8" + } + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "REQ.SECRET.GENERIC.URL", + "message": { + "text": "Hardcoded secrets were found", + "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nFilepath: usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc\nEvidence: htt************" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc" + }, + "region": { + "snippet": { + "text": "htt************" + } + } + } + } + ], + "fingerprints": { + "jfrogFingerprintHash": "9164423e88bbec9d1216bc5600eb7f9b" + } + } + ] + }, + { + "tool": { + "driver": { + "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sca", + "name": "JFrog Xray Scanner", + "rules": [ + { + "id": "CVE-2024-6119_debian:bookworm:openssl_3.0.13-1~deb12u1", + "shortDescription": { + "text": "[CVE-2024-6119] debian:bookworm:openssl 3.0.13-1~deb12u1" + }, + "help": { + "text": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | [3.0.14-1~deb12u2] |" + }, + "properties": { + "security-severity": "0.0" + } + }, + { + "id": "CVE-2024-45492_debian:bookworm:libexpat1_2.5.0-1", + "shortDescription": { + "text": "[CVE-2024-45492] debian:bookworm:libexpat1 2.5.0-1" + }, + "help": { + "text": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Not Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" + }, + "properties": { + "security-severity": "9.8" + } + }, + { + "id": "CVE-2023-51767_debian:bookworm:openssh-client:1_9.2p1-2+deb12u3", + "shortDescription": { + "text": "[CVE-2023-51767] debian:bookworm:openssh-client:1 9.2p1-2+deb12u3" + }, + "help": { + "text": "OpenSSH through 9.6, when common types of DRAM are used, might allow row hammer attacks (for authentication bypass) because the integer value of authenticated in mm_answer_authpassword does not resist flips of a single bit. NOTE: this is applicable to a certain threat model of attacker-victim co-location in which the attacker has user privileges.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.0 | Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" + }, + "properties": { + "security-severity": "7.0" + } + }, + { + "id": "CVE-2011-3374_debian:bookworm:apt_2.6.1", + "shortDescription": { + "text": "[CVE-2011-3374] debian:bookworm:apt 2.6.1" + }, + "help": { + "text": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.7 | Not Applicable | `sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ` | No fix available |" + }, + "properties": { + "security-severity": "3.7" + } + }, + { + "id": "CVE-2024-6119_debian:bookworm:libssl3_3.0.13-1~deb12u1", + "shortDescription": { + "text": "[CVE-2024-6119] debian:bookworm:libssl3 3.0.13-1~deb12u1" + }, + "help": { + "text": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" + }, + "properties": { + "security-severity": "0.0" + } + }, + { + "id": "XRAY-264729_cors.js_0.0.1-security", + "shortDescription": { + "text": "[XRAY-264729] cors.js 0.0.1-security" + }, + "help": { + "text": "Malicious package cors.js for Node.js", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 10.0 | Not Covered | `sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar ` | No fix available |" + }, + "properties": { + "security-severity": "10.0" + } + }, + { + "id": "CVE-2024-45490_debian:bookworm:libexpat1_2.5.0-1", + "shortDescription": { + "text": "[CVE-2024-45490] debian:bookworm:libexpat1 2.5.0-1" + }, + "help": { + "text": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Not Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" + }, + "properties": { + "security-severity": "9.8" + } + }, + { + "id": "CVE-2011-3374_debian:bookworm:libapt-pkg6.0_2.6.1", + "shortDescription": { + "text": "[CVE-2011-3374] debian:bookworm:libapt-pkg6.0 2.6.1" + }, + "help": { + "text": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.7 | Not Applicable | `sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ` | No fix available |" + }, + "properties": { + "security-severity": "3.7" + } + }, + { + "id": "CVE-2024-4741_debian:bookworm:libssl3_3.0.13-1~deb12u1", + "shortDescription": { + "text": "[CVE-2024-4741] debian:bookworm:libssl3 3.0.13-1~deb12u1" + }, + "help": { + "text": "CVE-2024-4741", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" + }, + "properties": { + "security-severity": "0.0" + } + }, + { + "id": "CVE-2024-4741_debian:bookworm:openssl_3.0.13-1~deb12u1", + "shortDescription": { + "text": "[CVE-2024-4741] debian:bookworm:openssl 3.0.13-1~deb12u1" + }, + "help": { + "text": "CVE-2024-4741", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | [3.0.14-1~deb12u1] |" + }, + "properties": { + "security-severity": "0.0" + } + }, + { + "id": "CVE-2024-38428_debian:bookworm:wget_1.21.3-1+b1", + "shortDescription": { + "text": "[CVE-2024-38428] debian:bookworm:wget 1.21.3-1+b1" + }, + "help": { + "text": "url.c in GNU Wget through 1.24.5 mishandles semicolons in the userinfo subcomponent of a URI, and thus there may be insecure behavior in which data that was supposed to be in the userinfo subcomponent is misinterpreted to be part of the host subcomponent.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.1 | Undetermined | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" + }, + "properties": { + "security-severity": "9.1" + } + } + ], + "version": "3.104.8" + } + }, + "invocations": [ + { + "executionSuccessful": true, + "workingDirectory": { + "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210535-1985298017/image.tar" + } + } + ], + "results": [ + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2024-6119_debian:bookworm:libssl3_3.0.13-1~deb12u1", + "ruleIndex": 4, + "level": "none", + "message": { + "text": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "5b5d2ba57a2eddf58f4579b7ebe42599" + } + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "[3.0.14-1~deb12u2]" + }, + "ruleId": "CVE-2024-6119_debian:bookworm:openssl_3.0.13-1~deb12u1", + "ruleIndex": 0, + "level": "none", + "message": { + "text": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "bd5908946de9c082f96e15217590eebc" + } + }, + { + "properties": { + "applicability": "Undetermined", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2024-38428_debian:bookworm:wget_1.21.3-1+b1", + "ruleIndex": 10, + "level": "error", + "message": { + "text": "[CVE-2024-38428] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-38428] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "db89861310f80a270a0a81f48d7dc974" + } + }, + { + "properties": { + "applicability": "Not Covered", + "fixedVersion": "No fix available" + }, + "ruleId": "XRAY-264729_cors.js_0.0.1-security", + "ruleIndex": 5, + "level": "error", + "message": { + "text": "[XRAY-264729] sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar ", + "markdown": "[XRAY-264729] sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" + } + }, + "logicalLocations": [ + { + "name": "ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "d653c414ef56560432b122358961104a" + } + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2024-45490_debian:bookworm:libexpat1_2.5.0-1", + "ruleIndex": 6, + "level": "error", + "message": { + "text": "[CVE-2024-45490] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", + "markdown": "[CVE-2024-45490] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + "logicalLocations": [ + { + "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "61be5170151428187e85ff7b27fd65b4" + } + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2024-45492_debian:bookworm:libexpat1_2.5.0-1", + "ruleIndex": 1, + "level": "error", + "message": { + "text": "[CVE-2024-45492] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", + "markdown": "[CVE-2024-45492] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + "logicalLocations": [ + { + "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "e47bb0a94451ed5111fabcf0ccaaeee6" + } + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2023-51767_debian:bookworm:openssh-client:1_9.2p1-2+deb12u3", + "ruleIndex": 2, + "level": "note", + "message": { + "text": "[CVE-2023-51767] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", + "markdown": "[CVE-2023-51767] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + "logicalLocations": [ + { + "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "fe7c1c90b3e7d340890027344468b42d" + } + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2011-3374_debian:bookworm:apt_2.6.1", + "ruleIndex": 3, + "level": "note", + "message": { + "text": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ", + "markdown": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + }, + "logicalLocations": [ + { + "name": "cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "81f98a6fd77d17d7647c0ae81410b506" + } + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2011-3374_debian:bookworm:libapt-pkg6.0_2.6.1", + "ruleIndex": 7, + "level": "note", + "message": { + "text": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ", + "markdown": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + }, + "logicalLocations": [ + { + "name": "cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "7933bf1c7b4635012e7571e82e619db6" + } + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2024-4741_debian:bookworm:libssl3_3.0.13-1~deb12u1", + "ruleIndex": 8, + "level": "none", + "message": { + "text": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "2c34553d9c75460bf14243ff13ba84c8" + } + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "[3.0.14-1~deb12u1]" + }, + "ruleId": "CVE-2024-4741_debian:bookworm:openssl_3.0.13-1~deb12u1", + "ruleIndex": 9, + "level": "none", + "message": { + "text": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" + } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "a374e04992f42ee827634927edd7e8d4" + } + } + ] + } + ] +} diff --git a/jobTestData/debug/simple.json b/jobTestData/debug/simple.json new file mode 100644 index 00000000..0fbd8a5a --- /dev/null +++ b/jobTestData/debug/simple.json @@ -0,0 +1,826 @@ +{ + "vulnerabilities": [ + { + "severity": "Critical", + "impactedPackageName": "debian:bookworm:wget", + "impactedPackageVersion": "1.21.3-1+b1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "url.c in GNU Wget through 1.24.5 mishandles semicolons in the userinfo subcomponent of a URI, and thus there may be insecure behavior in which data that was supposed to be in the userinfo subcomponent is misinterpreted to be part of the host subcomponent.", + "applicable": "Undetermined", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-38428", + "cvssV2": "", + "cvssV3": "9.1", + "applicability": { + "status": "Undetermined" + } + } + ], + "issueId": "XRAY-606103", + "references": [ + "https://git.savannah.gnu.org/cgit/wget.git/commit/?id=ed0c7c7e0e8f7298352646b2fd6e06a11e242ace", + "https://lists.gnu.org/archive/html/bug-wget/2024-06/msg00005.html", + "https://security-tracker.debian.org/tracker/CVE-2024-38428" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + { + "name": "debian:bookworm:wget", + "version": "1.21.3-1+b1", + "location": { + "file": "wget:1.21.3-1+b1" + } + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Critical", + "impactedPackageName": "cors.js", + "impactedPackageVersion": "0.0.1-security", + "impactedPackageType": "npm", + "components": [ + { + "name": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar", + "version": "", + "location": { + "file": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" + } + } + ], + "summary": "Malicious package cors.js for Node.js", + "applicable": "Not Covered", + "fixedVersions": null, + "cves": null, + "issueId": "XRAY-264729", + "references": [ + "https://registry.npmjs.com" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar", + "version": "", + "location": { + "file": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" + } + }, + { + "name": "cors.js", + "version": "0.0.1-security", + "location": { + "file": "usr/src/app/node_modules/cors.js/package.json" + } + } + ] + ], + "jfrogResearchInformation": { + "severity": "Critical", + "summary": "Malicious package cors.js for Node.js", + "details": "The package cors.js for Node.js contains malicious code that installs a persistent connectback shell. The package is typosquatting the popular `cors` package. When installed, the package opens a connectback shell to the hardcoded host `107.175.32.229` on TCP port 56173. The malicious payload achieves persistency by installing a cron job that repeats every 10 seconds - `*/10 * * * * *`", + "remediation": "As with any malware, the malicious package must be completely removed, and steps must be taken care to remediate the damage that was done by the malicious package -\n\n##### Removing the malicious package\n\nRun `npm uninstall cors.js`\n\n##### Refreshing stolen credentials\n\nMany malicious packages steal stored user credentials, focusing on the following -\n\n* [Browser autocomplete](https://jfrog.com/blog/malicious-pypi-packages-stealing-credit-cards-injecting-code/) data, such as saved passwords and credit cards\n* [Environment variables](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/) passed to the malicious code\n* [Stored Discord tokens](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)\n* AWS / GitHub credentials stored in cleartext files\n\nIt is highly recommended to change or revoke data that is stored in the infected machine at those locations\n\n##### Stopping malicious processes\n\nMany malicious packages start malicious processes such as [connectback shells](https://jfrog.com/blog/jfrog-discloses-3-remote-access-trojans-in-pypi/) or crypto-miners. Search for any unfamiliar processes that consume a large amount of CPU or a large amount of network traffic, and stop them. On Windows, this can be facilitated with [Sysinternals Process Explorer](https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer).\n\n##### Removing installed backdoors\n\nMany malicious packages install themselves as a [persistent backdoor](https://jfrog.com/blog/npm-supply-chain-attack-targets-german-based-companies/), in order to guarantee the malicious code survives a reboot. Search for any unfamiliar binaries set to be run on startup, and remove them. On Windows, this can be facilitated with [Sysinternals Autoruns](https://docs.microsoft.com/en-us/sysinternals/downloads/autoruns).\n\n##### Defining an Xray policy that blocks downloads of Artifacts with malicious packages\n\nIt is possible to [create an Xray policy](https://www.jfrog.com/confluence/display/JFROG/Creating+Xray+Policies+and+Rules) that will not allow artifacts with identified malicious packages to be downloaded from Artifactory. To create such a policy, add a new `Security` policy and set `Minimal Severity` to `Critical`. Under `Automatic Actions` check the `Block Download` action.\n\n##### Contacting the JFrog Security Research team for additional information\n\nOptionally, if you are unsure of the full impact of the malicious package and wish to get more details, the JFrog Security Research team can help you assess the potential damage from the installed malicious package.\n\nPlease contact us at research@jfrog.com with details of the affected artifact and the name of the identified malicious package." + } + }, + { + "severity": "Low", + "impactedPackageName": "debian:bookworm:openssh-client:1", + "impactedPackageVersion": "9.2p1-2+deb12u3", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + } + ], + "summary": "OpenSSH through 9.6, when common types of DRAM are used, might allow row hammer attacks (for authentication bypass) because the integer value of authenticated in mm_answer_authpassword does not resist flips of a single bit. NOTE: this is applicable to a certain threat model of attacker-victim co-location in which the attacker has user privileges.", + "applicable": "Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2023-51767", + "cvssV2": "", + "cvssV3": "7.0", + "applicability": { + "status": "Applicable", + "scannerDescription": "The CVE is always applicable.\n\nNote - The vulnerability is hardware-dependent." + } + } + ], + "issueId": "XRAY-585612", + "references": [ + "https://arxiv.org/abs/2309.02545", + "https://github.com/openssh/openssh-portable/blob/8241b9c0529228b4b86d88b1a6076fb9f97e4a99/monitor.c#L878", + "https://github.com/openssh/openssh-portable/blob/8241b9c0529228b4b86d88b1a6076fb9f97e4a99/auth-passwd.c#L77", + "https://bugzilla.redhat.com/show_bug.cgi?id=2255850", + "https://security-tracker.debian.org/tracker/CVE-2023-51767", + "https://ubuntu.com/security/CVE-2023-51767", + "https://security.netapp.com/advisory/ntap-20240125-0006/", + "https://access.redhat.com/security/cve/CVE-2023-51767" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + { + "name": "debian:bookworm:openssh-client:1", + "version": "9.2p1-2+deb12u3", + "location": { + "file": "openssh-client:1:9.2p1-2+deb12u3" + } + } + ] + ], + "jfrogResearchInformation": { + "severity": "Low", + "summary": "The RowHammer fault injection attack can theoretically lead to local authentication bypass in OpenSSH.", + "details": "[OpenSSH](https://www.openssh.com/) is a popular open-source implementation of the SSH (Secure Shell) protocol, providing encrypted communication over a network.\nIt was discovered that the OpenSSH authentication logic can be susceptible in some cases to a side-channel fault injection attack. The attack can theoretically be carried out by a local attacker which eventually bypass OpenSSH authentication mechanism.\n\nThis vulnerability currently lacks widely known published exploits, and its exploitation is considered highly complex. The intricacies of the attack, combined with the absence of well-documented exploits, contribute to the difficulty in achieving successful exploitation. Furthermore, it's essential to note that the susceptibility to this vulnerability is hardware-dependent, and the success of an attack relies on probabilities associated with the specific hardware configuration. \n\nThe vulnerability is theoretically exploitable by several different ways, the only two published ways are:\n\nIn the OpenSSH function `mm_answer_authpassword()`, a stack variable `authenticated`, is assigned to the value of the function `auth_password()` which returns 1/0 and then returned. If the value of `authenticated` is 1, the SSH connection will be established. Since `authenticated` is stored on the stack, therefore in DRAM, a local attacker could flip this 32-bit integer least significant bit, thus, bypass authentication.\n\nAnother possible exploit is the `result` stack variable in `auth_password()` function. It is initialized to 0 and set to 1 if the password is correct. \nSimilarly to the previous method, this attack requires a single bit flip of the `result` variable in order for the function to return 1 and bypass the authentication.\n\nAttackers can trigger the vulnerability via a RowHammer fault injection. The Rowhammer bug is a hardware reliability issue in which an attacker repeatedly accesses (hammers) DRAM cells to cause unauthorized changes in physically adjacent memory locations.\nSimply put:\n\n* A specific register value(`authenticated`/`result` value) is pushed onto the stack during program execution. \n* The stack, where the register value is stored, is identified to be located in a memory row susceptible to bit flips (flippable row) due to the RowHammer vulnerability in DRAM.\n* The attacker performs a series of rapid and repeated memory accesses to the adjacent rows of the flippable row in the DRAM. This repeated access exploits the RowHammer vulnerability, inducing bit flips in the targeted flippable row.\n* Due to the RowHammer effect, bit flips occur in the flippable row, potentially corrupting the data stored there.\n* After inducing bit flips in the flippable row, the attacker manipulates the program's control flow to pop the corrupted value from the stack into a register.\n* The register now holds a value that has been corrupted through the RowHammer attack. Now the `authenticated`/`result` variables hold this corrupted value thus it can lead to authentication bypass, as it may impact the control flow in a way advantageous to the attacker.", + "severityReasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The vulnerability depends on the OS and hardware. It was only evaluated in one test environment, therefore results for other conditions might differ. The attacker must be extremely familiar with the details of the exploited system (ex. know the exact hardware which is running the OS).", + "isPositive": true + }, + { + "name": "The issue can only be exploited by an attacker that can execute code on the vulnerable machine (excluding exceedingly rare circumstances)", + "isPositive": true + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Exploitation is extremely non-trivial (even theoretically), no public exploits have been published.", + "isPositive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The vulnerability's attack complexity is significantly higher than what the CVSS represents.", + "isPositive": true + } + ] + } + }, + { + "severity": "Unknown", + "impactedPackageName": "debian:bookworm:libssl3", + "impactedPackageVersion": "3.0.13-1~deb12u1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "CVE-2024-4741", + "applicable": "Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-4741", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called.", + "evidence": [ + { + "file": "usr/local/bin/node", + "reason": "References to the vulnerable functions were found" + } + ] + } + } + ], + "issueId": "XRAY-603657", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-4741" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + { + "name": "debian:bookworm:libssl3", + "version": "3.0.13-1~deb12u1", + "location": { + "file": "libssl3:3.0.13-1~deb12u1" + } + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Unknown", + "impactedPackageName": "debian:bookworm:openssl", + "impactedPackageVersion": "3.0.13-1~deb12u1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "CVE-2024-4741", + "applicable": "Applicable", + "fixedVersions": [ + "[3.0.14-1~deb12u1]" + ], + "cves": [ + { + "id": "CVE-2024-4741", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called.", + "evidence": [ + { + "file": "usr/local/bin/node", + "reason": "References to the vulnerable functions were found" + } + ] + } + } + ], + "issueId": "XRAY-603657", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-4741" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + { + "name": "debian:bookworm:openssl", + "version": "3.0.13-1~deb12u1", + "location": { + "file": "openssl:3.0.13-1~deb12u1" + } + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Unknown", + "impactedPackageName": "debian:bookworm:libssl3", + "impactedPackageVersion": "3.0.13-1~deb12u1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", + "applicable": "Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-6119", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`", + "evidence": [ + { + "file": "usr/local/bin/node", + "reason": "References to the vulnerable functions were found" + } + ] + } + } + ], + "issueId": "XRAY-632747", + "references": [ + "https://openssl-library.org/news/secadv/20240903.txt", + "https://github.com/openssl/openssl/commit/621f3729831b05ee828a3203eddb621d014ff2b2", + "https://github.com/openssl/openssl/commit/05f360d9e849a1b277db628f1f13083a7f8dd04f", + "https://security-tracker.debian.org/tracker/CVE-2024-6119", + "https://github.com/openssl/openssl/commit/7dfcee2cd2a63b2c64b9b4b0850be64cb695b0a0", + "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + { + "name": "debian:bookworm:libssl3", + "version": "3.0.13-1~deb12u1", + "location": { + "file": "libssl3:3.0.13-1~deb12u1" + } + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Out of bounds read in OpenSSL clients can lead to denial of service when using non-default TLS verification options and connecting to malicious TLS servers", + "severityReasons": [ + { + "name": "The issue has an exploit published", + "description": "The fix commit contains PoC certificates that trigger the denial of service issue" + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker must make the victim client connect to their malicious TLS server, in order to serve the malformed TLS certificate. The victim client must use OpenSSL and must enable non-default certificate verification options, either -\n\n* DNS verification - by using `X509_VERIFY_PARAM_set1_host` or `X509_check_host`\n* Email verification - by using ` X509_VERIFY_PARAM_set1_email` or `X509_check_email`", + "isPositive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Denial of service of a TLS clients only. This out of bounds read cannot lead to data disclosure.", + "isPositive": true + } + ] + } + }, + { + "severity": "Unknown", + "impactedPackageName": "debian:bookworm:openssl", + "impactedPackageVersion": "3.0.13-1~deb12u1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", + "applicable": "Applicable", + "fixedVersions": [ + "[3.0.14-1~deb12u2]" + ], + "cves": [ + { + "id": "CVE-2024-6119", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`", + "evidence": [ + { + "file": "usr/local/bin/node", + "reason": "References to the vulnerable functions were found" + } + ] + } + } + ], + "issueId": "XRAY-632747", + "references": [ + "https://openssl-library.org/news/secadv/20240903.txt", + "https://github.com/openssl/openssl/commit/621f3729831b05ee828a3203eddb621d014ff2b2", + "https://github.com/openssl/openssl/commit/05f360d9e849a1b277db628f1f13083a7f8dd04f", + "https://security-tracker.debian.org/tracker/CVE-2024-6119", + "https://github.com/openssl/openssl/commit/7dfcee2cd2a63b2c64b9b4b0850be64cb695b0a0", + "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + { + "name": "debian:bookworm:openssl", + "version": "3.0.13-1~deb12u1", + "location": { + "file": "openssl:3.0.13-1~deb12u1" + } + } + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Out of bounds read in OpenSSL clients can lead to denial of service when using non-default TLS verification options and connecting to malicious TLS servers", + "severityReasons": [ + { + "name": "The issue has an exploit published", + "description": "The fix commit contains PoC certificates that trigger the denial of service issue" + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker must make the victim client connect to their malicious TLS server, in order to serve the malformed TLS certificate. The victim client must use OpenSSL and must enable non-default certificate verification options, either -\n\n* DNS verification - by using `X509_VERIFY_PARAM_set1_host` or `X509_check_host`\n* Email verification - by using ` X509_VERIFY_PARAM_set1_email` or `X509_check_email`", + "isPositive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Denial of service of a TLS clients only. This out of bounds read cannot lead to data disclosure.", + "isPositive": true + } + ] + } + }, + { + "severity": "Critical", + "impactedPackageName": "debian:bookworm:libexpat1", + "impactedPackageVersion": "2.5.0-1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + } + ], + "summary": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", + "applicable": "Not Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-45490", + "cvssV2": "", + "cvssV3": "9.8", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `XML_Parse()`\n- `XML_ParseBuffer()`\n\nAn additional condition, which the scanner currently does not check, is that the `len` parameter which is passed to those functions is user-controlled." + } + } + ], + "issueId": "XRAY-632613", + "references": [ + "https://github.com/libexpat/libexpat/issues/887", + "https://security-tracker.debian.org/tracker/CVE-2024-45490", + "https://github.com/libexpat/libexpat/pull/890" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + { + "name": "debian:bookworm:libexpat1", + "version": "2.5.0-1", + "location": { + "file": "libexpat1:2.5.0-1" + } + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Critical", + "impactedPackageName": "debian:bookworm:libexpat1", + "impactedPackageVersion": "2.5.0-1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + } + ], + "summary": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", + "applicable": "Not Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-45492", + "cvssV2": "", + "cvssV3": "9.8", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the current binary was compiled with 32-bit architecture and if any of the vulnerable functions are called:\n\n- `XML_ParseBuffer()`\n- `XML_Parse()`\n\nNote - the vulnerability occurs when certain inputs are passed to those functions." + } + } + ], + "issueId": "XRAY-632612", + "references": [ + "https://github.com/libexpat/libexpat/issues/889", + "https://security-tracker.debian.org/tracker/CVE-2024-45492", + "https://github.com/libexpat/libexpat/pull/892" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + { + "name": "debian:bookworm:libexpat1", + "version": "2.5.0-1", + "location": { + "file": "libexpat1:2.5.0-1" + } + } + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Low", + "impactedPackageName": "debian:bookworm:apt", + "impactedPackageVersion": "2.6.1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", + "version": "", + "location": { + "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + } + ], + "summary": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", + "applicable": "Not Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2011-3374", + "cvssV2": "4.3", + "cvssV3": "3.7", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." + } + } + ], + "issueId": "XRAY-34417", + "references": [ + "https://people.canonical.com/~ubuntu-security/cve/2011/CVE-2011-3374.html", + "https://seclists.org/fulldisclosure/2011/Sep/221", + "https://ubuntu.com/security/CVE-2011-3374", + "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=642480", + "https://access.redhat.com/security/cve/cve-2011-3374", + "https://snyk.io/vuln/SNYK-LINUX-APT-116518", + "https://security-tracker.debian.org/tracker/CVE-2011-3374" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", + "version": "", + "location": { + "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + }, + { + "name": "debian:bookworm:apt", + "version": "2.6.1", + "location": { + "file": "apt:2.6.1" + } + } + ] + ], + "jfrogResearchInformation": { + "severity": "High", + "summary": "Improper signature validation in apt-key may enable Man-in-the-Middle attacks and result in code execution.", + "details": "`apt-key` is [`apt`](https://github.com/Debian/apt)'s key management utility, and is used to manage the keys that are used by `apt` to authenticate packages.\n\nA vulnerability in `apt-key`'s `net-update` function exists, in which [`GPG`](https://www.gnupg.org/) keys, that are used for signing packages and validating their authenticity, aren't validated correctly. The `net-update` function pulls the signing keys that should be added from an insecure location (`http://...`), exposing it to a Man-in-the-Middle attack in which malicious signing keys could be added to the system's keyring. This issue happens due to a vulnerability in the `add_keys_with_veirfy_against_master_keyring()` function, which allows adding signing keys without proper signature validation. \n\nThis vulnerability then potentially allows a malicious actor to perform a Man-in-the-Middle attack on a target, by making it validate malicious packages that were signed with the `GPG` signing key used by the attacker. Effectively, this means that `apt` can be duped to install malicious services and daemons with root privileges.\n\nThe conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man In The Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from [python-apt](https://pypi.org/project/python-apt/) Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.\n\nDo note that `apt-key` is **deprecated** and shouldn't be used, and in most Debian versions `ARCHIVE_KEYRING_URI` is not defined, making this vulnerability unexploitable in most Debian systems.", + "severityReasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the python-apt Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", + "isPositive": true + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "This vulnerability is remotely exploitable when the applicability conditions apply." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Remote code execution is possible when the applicability conditions apply." + }, + { + "name": "The issue has an exploit published", + "description": "The reporter of this issue has provided a GPG key that can be used for an actual attack, as well as a simple PoC example." + } + ], + "remediation": "##### Deployment mitigations\n\n* Dot not execute `apt-key` command, as it is deprecated.\n* Remove the URI configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`." + } + }, + { + "severity": "Low", + "impactedPackageName": "debian:bookworm:libapt-pkg6.0", + "impactedPackageVersion": "2.6.1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", + "version": "", + "location": { + "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + } + ], + "summary": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", + "applicable": "Not Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2011-3374", + "cvssV2": "4.3", + "cvssV3": "3.7", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." + } + } + ], + "issueId": "XRAY-34417", + "references": [ + "https://people.canonical.com/~ubuntu-security/cve/2011/CVE-2011-3374.html", + "https://seclists.org/fulldisclosure/2011/Sep/221", + "https://ubuntu.com/security/CVE-2011-3374", + "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=642480", + "https://access.redhat.com/security/cve/cve-2011-3374", + "https://snyk.io/vuln/SNYK-LINUX-APT-116518", + "https://security-tracker.debian.org/tracker/CVE-2011-3374" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, + { + "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", + "version": "", + "location": { + "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + }, + { + "name": "debian:bookworm:libapt-pkg6.0", + "version": "2.6.1", + "location": { + "file": "libapt-pkg6.0:2.6.1" + } + } + ] + ], + "jfrogResearchInformation": { + "severity": "High", + "summary": "Improper signature validation in apt-key may enable Man-in-the-Middle attacks and result in code execution.", + "details": "`apt-key` is [`apt`](https://github.com/Debian/apt)'s key management utility, and is used to manage the keys that are used by `apt` to authenticate packages.\n\nA vulnerability in `apt-key`'s `net-update` function exists, in which [`GPG`](https://www.gnupg.org/) keys, that are used for signing packages and validating their authenticity, aren't validated correctly. The `net-update` function pulls the signing keys that should be added from an insecure location (`http://...`), exposing it to a Man-in-the-Middle attack in which malicious signing keys could be added to the system's keyring. This issue happens due to a vulnerability in the `add_keys_with_veirfy_against_master_keyring()` function, which allows adding signing keys without proper signature validation. \n\nThis vulnerability then potentially allows a malicious actor to perform a Man-in-the-Middle attack on a target, by making it validate malicious packages that were signed with the `GPG` signing key used by the attacker. Effectively, this means that `apt` can be duped to install malicious services and daemons with root privileges.\n\nThe conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man In The Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from [python-apt](https://pypi.org/project/python-apt/) Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.\n\nDo note that `apt-key` is **deprecated** and shouldn't be used, and in most Debian versions `ARCHIVE_KEYRING_URI` is not defined, making this vulnerability unexploitable in most Debian systems.", + "severityReasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the python-apt Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", + "isPositive": true + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "This vulnerability is remotely exploitable when the applicability conditions apply." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Remote code execution is possible when the applicability conditions apply." + }, + { + "name": "The issue has an exploit published", + "description": "The reporter of this issue has provided a GPG key that can be used for an actual attack, as well as a simple PoC example." + } + ], + "remediation": "##### Deployment mitigations\n\n* Dot not execute `apt-key` command, as it is deprecated.\n* Remove the URI configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`." + } + } + ], + "securityViolations": null, + "licensesViolations": null, + "licenses": null, + "operationalRiskViolations": null, + "secrets": [ + { + "severity": "Medium", + "file": "usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc", + "snippet": "htt************", + "finding": "Hardcoded secrets were found", + "scannerDescription": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + { + "severity": "Medium", + "file": "private/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/tmpsfyn_3d1/unpacked/filesystem/blobs/sha256/9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0/usr/src/app/server/index.js", + "startLine": 5, + "startColumn": 7, + "endLine": 5, + "endColumn": 57, + "snippet": "tok************", + "finding": "Hardcoded secrets were found", + "scannerDescription": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + { + "severity": "Medium", + "file": "private/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/tmpsfyn_3d1/unpacked/filesystem/blobs/sha256/9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0/usr/src/app/server/index.js", + "startLine": 6, + "startColumn": 14, + "endLine": 6, + "endColumn": 24, + "snippet": "eyJ************", + "finding": "Secret keys were found", + "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + } + ], + "iacViolations": null, + "sastViolations": null, + "errors": null +} diff --git a/tests/testdata/output/dockerscan/docker_sarif.json b/tests/testdata/output/dockerscan/docker_sarif.json index adda131f..2ec85075 100644 --- a/tests/testdata/output/dockerscan/docker_sarif.json +++ b/tests/testdata/output/dockerscan/docker_sarif.json @@ -1,778 +1,778 @@ { - "version": "2.1.0", - "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", - "runs": [ - { - "tool": { - "driver": { - "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", - "name": "JFrog Binary Secrets Scanner", - "rules": [ - { - "id": "REQ.SECRET.GENERIC.TEXT", - "name": "REQ.SECRET.GENERIC.TEXT", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.TEXT" - }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "help": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive" - } + "version": "2.1.0", + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "runs": [ + { + "tool": { + "driver": { + "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", + "name": "JFrog Binary Secrets Scanner", + "rules": [ + { + "id": "REQ.SECRET.GENERIC.TEXT", + "name": "REQ.SECRET.GENERIC.TEXT", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.TEXT" }, - { - "id": "REQ.SECRET.GENERIC.CODE", - "name": "REQ.SECRET.GENERIC.CODE", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.CODE" - }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "help": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "applicable", - "conclusion": "negative", - "security-severity": "6.9" - } + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" }, - { - "id": "REQ.SECRET.KEYS", - "name": "REQ.SECRET.KEYS", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.SECRET.KEYS" - }, - "fullDescription": { - "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", - "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" - }, - "help": { - "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", - "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" - }, - "properties": { - "applicability": "applicable", - "conclusion": "negative", - "security-severity": "6.9" - } + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" }, - { - "id": "REQ.CRED.PUBLIC-ONLY", - "name": "REQ.CRED.PUBLIC-ONLY", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.CRED.PUBLIC-ONLY" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "help": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "undetermined", - "conclusion": "private" - } + "properties": { + "applicability": "not_applicable", + "conclusion": "positive" + } + }, + { + "id": "REQ.SECRET.GENERIC.CODE", + "name": "REQ.SECRET.GENERIC.CODE", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.CODE" }, - { - "id": "REQ.SECRET.GENERIC.URL", - "name": "REQ.SECRET.GENERIC.URL", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.URL" - }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "help": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "applicable", - "conclusion": "negative", - "security-severity": "6.9" - } + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" } - ], - "version": "1.0" - } - }, - "invocations": [ - { - "arguments": [ - "/Users/user/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", - "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210780-681556384/Secrets_1726210839/config.yaml" - ], - "executionSuccessful": true, - "workingDirectory": { - "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210535-1985298017/image.tar" - } - } - ], - "results": [ - { - "properties": { - "metadata": "", - "tokenValidation": "" }, - "ruleId": "REQ.SECRET.GENERIC.CODE", - "message": { - "text": "Hardcoded secrets were found", - "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: usr/src/app/server/index.js\nEvidence: tok************" + { + "id": "REQ.SECRET.KEYS", + "name": "REQ.SECRET.KEYS", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.KEYS" + }, + "fullDescription": { + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + "help": { + "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", + "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "usr/src/app/server/index.js" - }, - "region": { - "startLine": 5, - "startColumn": 7, - "endLine": 5, - "endColumn": 57, - "snippet": { - "text": "tok************" - } + { + "id": "REQ.CRED.PUBLIC-ONLY", + "name": "REQ.CRED.PUBLIC-ONLY", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.CRED.PUBLIC-ONLY" + }, + "fullDescription": { + "text": "", + "markdown": "" + }, + "help": { + "text": "", + "markdown": "" + }, + "properties": { + "applicability": "undetermined", + "conclusion": "private" + } + }, + { + "id": "REQ.SECRET.GENERIC.URL", + "name": "REQ.SECRET.GENERIC.URL", + "shortDescription": { + "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.URL" + }, + "fullDescription": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "help": { + "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", + "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + "properties": { + "applicability": "applicable", + "conclusion": "negative", + "security-severity": "6.9" + } + } + ], + "version": "1.0" + } + }, + "invocations": [ + { + "arguments": [ + "/Users/user/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", + "scan", + "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210780-681556384/Secrets_1726210839/config.yaml" + ], + "executionSuccessful": true, + "workingDirectory": { + "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210535-1985298017/image.tar" + } + } + ], + "results": [ + { + "properties": { + "metadata": "", + "tokenValidation": "" + }, + "ruleId": "REQ.SECRET.GENERIC.CODE", + "message": { + "text": "Hardcoded secrets were found", + "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: usr/src/app/server/index.js\nEvidence: tok************" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "usr/src/app/server/index.js" + }, + "region": { + "startLine": 5, + "startColumn": 7, + "endLine": 5, + "endColumn": 57, + "snippet": { + "text": "tok************" } - }, - "logicalLocations": [ - { - "name": "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } + } + }, + "logicalLocations": [ + { + "name": "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", + "kind": "layer", + "properties": { + "algorithm": "sha256" } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "00436fac1d19ea36302f14e892926efb" + } + ] } + ], + "fingerprints": { + "jfrogFingerprintHash": "00436fac1d19ea36302f14e892926efb" + } + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" }, - { - "properties": { - "metadata": "", - "tokenValidation": "" - }, - "ruleId": "REQ.SECRET.KEYS", - "message": { - "text": "Secret keys were found", - "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: usr/src/app/server/index.js\nEvidence: eyJ************" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "usr/src/app/server/index.js" - }, - "region": { - "startLine": 6, - "startColumn": 14, - "endLine": 6, - "endColumn": 24, - "snippet": { - "text": "eyJ************" - } + "ruleId": "REQ.SECRET.KEYS", + "message": { + "text": "Secret keys were found", + "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: usr/src/app/server/index.js\nEvidence: eyJ************" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "usr/src/app/server/index.js" + }, + "region": { + "startLine": 6, + "startColumn": 14, + "endLine": 6, + "endColumn": 24, + "snippet": { + "text": "eyJ************" } - }, - "logicalLocations": [ - { - "name": "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } + } + }, + "logicalLocations": [ + { + "name": "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", + "kind": "layer", + "properties": { + "algorithm": "sha256" } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "2550dbdb124696ae8fcc5cfd6f2b65b8" + } + ] } + ], + "fingerprints": { + "jfrogFingerprintHash": "2550dbdb124696ae8fcc5cfd6f2b65b8" + } + }, + { + "properties": { + "metadata": "", + "tokenValidation": "" }, - { - "properties": { - "metadata": "", - "tokenValidation": "" - }, - "ruleId": "REQ.SECRET.GENERIC.URL", - "message": { - "text": "Hardcoded secrets were found", - "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nFilepath: usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc\nEvidence: htt************" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc" - }, - "region": { - "snippet": { - "text": "htt************" - } + "ruleId": "REQ.SECRET.GENERIC.URL", + "message": { + "text": "Hardcoded secrets were found", + "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nFilepath: usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc\nEvidence: htt************" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc" + }, + "region": { + "snippet": { + "text": "htt************" } } } - ], - "fingerprints": { - "jfrogFingerprintHash": "9164423e88bbec9d1216bc5600eb7f9b" } + ], + "fingerprints": { + "jfrogFingerprintHash": "9164423e88bbec9d1216bc5600eb7f9b" } - ] - }, - { - "tool": { - "driver": { - "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sca", - "name": "JFrog Xray Scanner", - "rules": [ - { - "id": "CVE-2024-6119_debian:bookworm:openssl_3.0.13-1~deb12u1", - "shortDescription": { - "text": "[CVE-2024-6119] debian:bookworm:openssl 3.0.13-1~deb12u1" - }, - "help": { - "text": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | [3.0.14-1~deb12u2] |" - }, - "properties": { - "security-severity": "0.0" - } + } + ] + }, + { + "tool": { + "driver": { + "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sca", + "name": "JFrog Xray Scanner", + "rules": [ + { + "id": "CVE-2024-45490_debian:bookworm:libexpat1_2.5.0-1", + "shortDescription": { + "text": "[CVE-2024-45490] debian:bookworm:libexpat1 2.5.0-1" }, - { - "id": "CVE-2024-38428_debian:bookworm:wget_1.21.3-1+b1", - "shortDescription": { - "text": "[CVE-2024-38428] debian:bookworm:wget 1.21.3-1+b1" - }, - "help": { - "text": "url.c in GNU Wget through 1.24.5 mishandles semicolons in the userinfo subcomponent of a URI, and thus there may be insecure behavior in which data that was supposed to be in the userinfo subcomponent is misinterpreted to be part of the host subcomponent.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.1 | Undetermined | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" - }, - "properties": { - "security-severity": "9.1" - } + "help": { + "text": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Not Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" }, - { - "id": "CVE-2024-45490_debian:bookworm:libexpat1_2.5.0-1", - "shortDescription": { - "text": "[CVE-2024-45490] debian:bookworm:libexpat1 2.5.0-1" - }, - "help": { - "text": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Not Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" - }, - "properties": { - "security-severity": "9.8" - } + "properties": { + "security-severity": "9.8" + } + }, + { + "id": "CVE-2011-3374_debian:bookworm:apt_2.6.1", + "shortDescription": { + "text": "[CVE-2011-3374] debian:bookworm:apt 2.6.1" }, - { - "id": "CVE-2024-45492_debian:bookworm:libexpat1_2.5.0-1", - "shortDescription": { - "text": "[CVE-2024-45492] debian:bookworm:libexpat1 2.5.0-1" - }, - "help": { - "text": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Not Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" - }, - "properties": { - "security-severity": "9.8" - } + "help": { + "text": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.7 | Not Applicable | `sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ` | No fix available |" }, - { - "id": "CVE-2024-4741_debian:bookworm:openssl_3.0.13-1~deb12u1", - "shortDescription": { - "text": "[CVE-2024-4741] debian:bookworm:openssl 3.0.13-1~deb12u1" - }, - "help": { - "text": "CVE-2024-4741", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | [3.0.14-1~deb12u1] |" - }, - "properties": { - "security-severity": "0.0" - } + "properties": { + "security-severity": "3.7" + } + }, + { + "id": "CVE-2024-38428_debian:bookworm:wget_1.21.3-1+b1", + "shortDescription": { + "text": "[CVE-2024-38428] debian:bookworm:wget 1.21.3-1+b1" }, - { - "id": "CVE-2024-6119_debian:bookworm:libssl3_3.0.13-1~deb12u1", - "shortDescription": { - "text": "[CVE-2024-6119] debian:bookworm:libssl3 3.0.13-1~deb12u1" - }, - "help": { - "text": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" - }, - "properties": { - "security-severity": "0.0" - } + "help": { + "text": "url.c in GNU Wget through 1.24.5 mishandles semicolons in the userinfo subcomponent of a URI, and thus there may be insecure behavior in which data that was supposed to be in the userinfo subcomponent is misinterpreted to be part of the host subcomponent.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.1 | Undetermined | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" }, - { - "id": "XRAY-264729_cors.js_0.0.1-security", - "shortDescription": { - "text": "[XRAY-264729] cors.js 0.0.1-security" - }, - "help": { - "text": "Malicious package cors.js for Node.js", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 10.0 | Not Covered | `sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar ` | No fix available |" - }, - "properties": { - "security-severity": "10.0" - } + "properties": { + "security-severity": "9.1" + } + }, + { + "id": "XRAY-264729_cors.js_0.0.1-security", + "shortDescription": { + "text": "[XRAY-264729] cors.js 0.0.1-security" }, - { - "id": "CVE-2023-51767_debian:bookworm:openssh-client:1_9.2p1-2+deb12u3", - "shortDescription": { - "text": "[CVE-2023-51767] debian:bookworm:openssh-client:1 9.2p1-2+deb12u3" - }, - "help": { - "text": "OpenSSH through 9.6, when common types of DRAM are used, might allow row hammer attacks (for authentication bypass) because the integer value of authenticated in mm_answer_authpassword does not resist flips of a single bit. NOTE: this is applicable to a certain threat model of attacker-victim co-location in which the attacker has user privileges.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.0 | Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" - }, - "properties": { - "security-severity": "7.0" - } + "help": { + "text": "Malicious package cors.js for Node.js", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 10.0 | Not Covered | `sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar ` | No fix available |" }, - { - "id": "CVE-2011-3374_debian:bookworm:apt_2.6.1", - "shortDescription": { - "text": "[CVE-2011-3374] debian:bookworm:apt 2.6.1" - }, - "help": { - "text": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.7 | Not Applicable | `sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ` | No fix available |" - }, - "properties": { - "security-severity": "3.7" - } + "properties": { + "security-severity": "10.0" + } + }, + { + "id": "CVE-2024-45492_debian:bookworm:libexpat1_2.5.0-1", + "shortDescription": { + "text": "[CVE-2024-45492] debian:bookworm:libexpat1 2.5.0-1" }, - { - "id": "CVE-2011-3374_debian:bookworm:libapt-pkg6.0_2.6.1", - "shortDescription": { - "text": "[CVE-2011-3374] debian:bookworm:libapt-pkg6.0 2.6.1" - }, - "help": { - "text": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.7 | Not Applicable | `sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ` | No fix available |" - }, - "properties": { - "security-severity": "3.7" - } + "help": { + "text": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Not Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" }, - { - "id": "CVE-2024-4741_debian:bookworm:libssl3_3.0.13-1~deb12u1", - "shortDescription": { - "text": "[CVE-2024-4741] debian:bookworm:libssl3 3.0.13-1~deb12u1" - }, - "help": { - "text": "CVE-2024-4741", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" - }, - "properties": { - "security-severity": "0.0" - } + "properties": { + "security-severity": "9.8" } - ], - "version": "3.104.8" - } - }, - "invocations": [ - { - "executionSuccessful": true, - "workingDirectory": { - "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210535-1985298017/image.tar" - } - } - ], - "results": [ - { - "properties": { - "applicability": "Applicable", - "fixedVersion": "No fix available" }, - "ruleId": "CVE-2024-6119_debian:bookworm:libssl3_3.0.13-1~deb12u1", - "ruleIndex": 5, - "level": "none", - "message": { - "text": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", - "markdown": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + { + "id": "CVE-2023-51767_debian:bookworm:openssh-client:1_9.2p1-2+deb12u3", + "shortDescription": { + "text": "[CVE-2023-51767] debian:bookworm:openssh-client:1 9.2p1-2+deb12u3" + }, + "help": { + "text": "OpenSSH through 9.6, when common types of DRAM are used, might allow row hammer attacks (for authentication bypass) because the integer value of authenticated in mm_answer_authpassword does not resist flips of a single bit. NOTE: this is applicable to a certain threat model of attacker-victim co-location in which the attacker has user privileges.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.0 | Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" + }, + "properties": { + "security-severity": "7.0" + } }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - "logicalLocations": [ - { - "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] + { + "id": "CVE-2011-3374_debian:bookworm:libapt-pkg6.0_2.6.1", + "shortDescription": { + "text": "[CVE-2011-3374] debian:bookworm:libapt-pkg6.0 2.6.1" + }, + "help": { + "text": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.7 | Not Applicable | `sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ` | No fix available |" + }, + "properties": { + "security-severity": "3.7" } - ], - "fingerprints": { - "jfrogFingerprintHash": "5b5d2ba57a2eddf58f4579b7ebe42599" - } - }, - { - "properties": { - "applicability": "Applicable", - "fixedVersion": "[3.0.14-1~deb12u2]" }, - "ruleId": "CVE-2024-6119_debian:bookworm:openssl_3.0.13-1~deb12u1", - "ruleIndex": 0, - "level": "none", - "message": { - "text": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", - "markdown": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + { + "id": "CVE-2024-4741_debian:bookworm:openssl_3.0.13-1~deb12u1", + "shortDescription": { + "text": "[CVE-2024-4741] debian:bookworm:openssl 3.0.13-1~deb12u1" + }, + "help": { + "text": "CVE-2024-4741", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | [3.0.14-1~deb12u1] |" + }, + "properties": { + "security-severity": "0.0" + } }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - "logicalLocations": [ - { - "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] + { + "id": "CVE-2024-6119_debian:bookworm:libssl3_3.0.13-1~deb12u1", + "shortDescription": { + "text": "[CVE-2024-6119] debian:bookworm:libssl3 3.0.13-1~deb12u1" + }, + "help": { + "text": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" + }, + "properties": { + "security-severity": "0.0" } - ], - "fingerprints": { - "jfrogFingerprintHash": "bd5908946de9c082f96e15217590eebc" - } - }, - { - "properties": { - "applicability": "Undetermined", - "fixedVersion": "No fix available" }, - "ruleId": "CVE-2024-38428_debian:bookworm:wget_1.21.3-1+b1", - "ruleIndex": 1, - "level": "error", - "message": { - "text": "[CVE-2024-38428] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", - "markdown": "[CVE-2024-38428] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + { + "id": "CVE-2024-6119_debian:bookworm:openssl_3.0.13-1~deb12u1", + "shortDescription": { + "text": "[CVE-2024-6119] debian:bookworm:openssl 3.0.13-1~deb12u1" + }, + "help": { + "text": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | [3.0.14-1~deb12u2] |" + }, + "properties": { + "security-severity": "0.0" + } }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - "logicalLocations": [ - { - "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] + { + "id": "CVE-2024-4741_debian:bookworm:libssl3_3.0.13-1~deb12u1", + "shortDescription": { + "text": "[CVE-2024-4741] debian:bookworm:libssl3 3.0.13-1~deb12u1" + }, + "help": { + "text": "CVE-2024-4741", + "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" + }, + "properties": { + "security-severity": "0.0" } - ], - "fingerprints": { - "jfrogFingerprintHash": "db89861310f80a270a0a81f48d7dc974" } + ], + "version": "3.104.8" + } + }, + "invocations": [ + { + "executionSuccessful": true, + "workingDirectory": { + "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210535-1985298017/image.tar" + } + } + ], + "results": [ + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "No fix available" }, - { - "properties": { - "applicability": "Not Covered", - "fixedVersion": "No fix available" - }, - "ruleId": "XRAY-264729_cors.js_0.0.1-security", - "ruleIndex": 6, - "level": "error", - "message": { - "text": "[XRAY-264729] sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar ", - "markdown": "[XRAY-264729] sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" - } - }, - "logicalLocations": [ - { - "name": "ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } + "ruleId": "CVE-2024-6119_debian:bookworm:libssl3_3.0.13-1~deb12u1", + "ruleIndex": 8, + "level": "none", + "message": { + "text": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "d653c414ef56560432b122358961104a" + } + ] } + ], + "fingerprints": { + "jfrogFingerprintHash": "5b5d2ba57a2eddf58f4579b7ebe42599" + } + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "[3.0.14-1~deb12u2]" }, - { - "properties": { - "applicability": "Not Applicable", - "fixedVersion": "No fix available" - }, - "ruleId": "CVE-2024-45490_debian:bookworm:libexpat1_2.5.0-1", - "ruleIndex": 2, - "level": "error", - "message": { - "text": "[CVE-2024-45490] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", - "markdown": "[CVE-2024-45490] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - }, - "logicalLocations": [ - { - "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } + "ruleId": "CVE-2024-6119_debian:bookworm:openssl_3.0.13-1~deb12u1", + "ruleIndex": 9, + "level": "none", + "message": { + "text": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "61be5170151428187e85ff7b27fd65b4" + } + ] } + ], + "fingerprints": { + "jfrogFingerprintHash": "bd5908946de9c082f96e15217590eebc" + } + }, + { + "properties": { + "applicability": "Undetermined", + "fixedVersion": "No fix available" }, - { - "properties": { - "applicability": "Not Applicable", - "fixedVersion": "No fix available" - }, - "ruleId": "CVE-2024-45492_debian:bookworm:libexpat1_2.5.0-1", - "ruleIndex": 3, - "level": "error", - "message": { - "text": "[CVE-2024-45492] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", - "markdown": "[CVE-2024-45492] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - }, - "logicalLocations": [ - { - "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } + "ruleId": "CVE-2024-38428_debian:bookworm:wget_1.21.3-1+b1", + "ruleIndex": 2, + "level": "error", + "message": { + "text": "[CVE-2024-38428] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-38428] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "e47bb0a94451ed5111fabcf0ccaaeee6" + } + ] } + ], + "fingerprints": { + "jfrogFingerprintHash": "db89861310f80a270a0a81f48d7dc974" + } + }, + { + "properties": { + "applicability": "Not Covered", + "fixedVersion": "No fix available" }, - { - "properties": { - "applicability": "Applicable", - "fixedVersion": "No fix available" - }, - "ruleId": "CVE-2023-51767_debian:bookworm:openssh-client:1_9.2p1-2+deb12u3", - "ruleIndex": 7, - "level": "note", - "message": { - "text": "[CVE-2023-51767] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", - "markdown": "[CVE-2023-51767] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - }, - "logicalLocations": [ - { - "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } + "ruleId": "XRAY-264729_cors.js_0.0.1-security", + "ruleIndex": 3, + "level": "error", + "message": { + "text": "[XRAY-264729] sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar ", + "markdown": "[XRAY-264729] sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" + } + }, + "logicalLocations": [ + { + "name": "ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f", + "kind": "layer", + "properties": { + "algorithm": "sha256" } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "fe7c1c90b3e7d340890027344468b42d" + } + ] } + ], + "fingerprints": { + "jfrogFingerprintHash": "d653c414ef56560432b122358961104a" + } + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "No fix available" }, - { - "properties": { - "applicability": "Not Applicable", - "fixedVersion": "No fix available" - }, - "ruleId": "CVE-2011-3374_debian:bookworm:apt_2.6.1", - "ruleIndex": 8, - "level": "note", - "message": { - "text": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ", - "markdown": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" - } - }, - "logicalLocations": [ - { - "name": "cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } + "ruleId": "CVE-2024-45490_debian:bookworm:libexpat1_2.5.0-1", + "ruleIndex": 0, + "level": "error", + "message": { + "text": "[CVE-2024-45490] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", + "markdown": "[CVE-2024-45490] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + "logicalLocations": [ + { + "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", + "kind": "layer", + "properties": { + "algorithm": "sha256" } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "81f98a6fd77d17d7647c0ae81410b506" + } + ] } + ], + "fingerprints": { + "jfrogFingerprintHash": "61be5170151428187e85ff7b27fd65b4" + } + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "No fix available" }, - { - "properties": { - "applicability": "Not Applicable", - "fixedVersion": "No fix available" - }, - "ruleId": "CVE-2011-3374_debian:bookworm:libapt-pkg6.0_2.6.1", - "ruleIndex": 9, - "level": "note", - "message": { - "text": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ", - "markdown": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + "ruleId": "CVE-2024-45492_debian:bookworm:libexpat1_2.5.0-1", + "ruleIndex": 4, + "level": "error", + "message": { + "text": "[CVE-2024-45492] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", + "markdown": "[CVE-2024-45492] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + "logicalLocations": [ + { + "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", + "kind": "layer", + "properties": { + "algorithm": "sha256" } - }, - "logicalLocations": [ - { - "name": "cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "e47bb0a94451ed5111fabcf0ccaaeee6" + } + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2023-51767_debian:bookworm:openssh-client:1_9.2p1-2+deb12u3", + "ruleIndex": 5, + "level": "note", + "message": { + "text": "[CVE-2023-51767] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", + "markdown": "[CVE-2023-51767] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + }, + "logicalLocations": [ + { + "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", + "kind": "layer", + "properties": { + "algorithm": "sha256" } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "7933bf1c7b4635012e7571e82e619db6" + } + ] } + ], + "fingerprints": { + "jfrogFingerprintHash": "fe7c1c90b3e7d340890027344468b42d" + } + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "No fix available" }, - { - "properties": { - "applicability": "Applicable", - "fixedVersion": "No fix available" - }, - "ruleId": "CVE-2024-4741_debian:bookworm:libssl3_3.0.13-1~deb12u1", - "ruleIndex": 10, - "level": "none", - "message": { - "text": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", - "markdown": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + "ruleId": "CVE-2011-3374_debian:bookworm:apt_2.6.1", + "ruleIndex": 1, + "level": "note", + "message": { + "text": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ", + "markdown": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + }, + "logicalLocations": [ + { + "name": "cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e", + "kind": "layer", + "properties": { + "algorithm": "sha256" } - }, - "logicalLocations": [ - { - "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "81f98a6fd77d17d7647c0ae81410b506" + } + }, + { + "properties": { + "applicability": "Not Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2011-3374_debian:bookworm:libapt-pkg6.0_2.6.1", + "ruleIndex": 6, + "level": "note", + "message": { + "text": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ", + "markdown": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + }, + "logicalLocations": [ + { + "name": "cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e", + "kind": "layer", + "properties": { + "algorithm": "sha256" } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "2c34553d9c75460bf14243ff13ba84c8" + } + ] } + ], + "fingerprints": { + "jfrogFingerprintHash": "7933bf1c7b4635012e7571e82e619db6" + } + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "[3.0.14-1~deb12u1]" }, - { - "properties": { - "applicability": "Applicable", - "fixedVersion": "[3.0.14-1~deb12u1]" - }, - "ruleId": "CVE-2024-4741_debian:bookworm:openssl_3.0.13-1~deb12u1", - "ruleIndex": 4, - "level": "none", - "message": { - "text": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", - "markdown": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + "ruleId": "CVE-2024-4741_debian:bookworm:openssl_3.0.13-1~deb12u1", + "ruleIndex": 7, + "level": "none", + "message": { + "text": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" } - }, - "logicalLocations": [ - { - "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } + } + ] + } + ], + "fingerprints": { + "jfrogFingerprintHash": "a374e04992f42ee827634927edd7e8d4" + } + }, + { + "properties": { + "applicability": "Applicable", + "fixedVersion": "No fix available" + }, + "ruleId": "CVE-2024-4741_debian:bookworm:libssl3_3.0.13-1~deb12u1", + "ruleIndex": 10, + "level": "none", + "message": { + "text": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", + "markdown": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + }, + "logicalLocations": [ + { + "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", + "kind": "layer", + "properties": { + "algorithm": "sha256" } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "a374e04992f42ee827634927edd7e8d4" + } + ] } + ], + "fingerprints": { + "jfrogFingerprintHash": "2c34553d9c75460bf14243ff13ba84c8" } - ] - } - ] - } \ No newline at end of file + } + ] + } + ] +} diff --git a/tests/testdata/output/dockerscan/docker_simple_json.json b/tests/testdata/output/dockerscan/docker_simple_json.json index bb5a715a..0fbd8a5a 100644 --- a/tests/testdata/output/dockerscan/docker_simple_json.json +++ b/tests/testdata/output/dockerscan/docker_simple_json.json @@ -1,826 +1,826 @@ { - "vulnerabilities": [ - { - "severity": "Critical", - "impactedPackageName": "debian:bookworm:wget", - "impactedPackageVersion": "1.21.3-1+b1", - "impactedPackageType": "Debian", - "components": [ + "vulnerabilities": [ + { + "severity": "Critical", + "impactedPackageName": "debian:bookworm:wget", + "impactedPackageVersion": "1.21.3-1+b1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "url.c in GNU Wget through 1.24.5 mishandles semicolons in the userinfo subcomponent of a URI, and thus there may be insecure behavior in which data that was supposed to be in the userinfo subcomponent is misinterpreted to be part of the host subcomponent.", + "applicable": "Undetermined", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-38428", + "cvssV2": "", + "cvssV3": "9.1", + "applicability": { + "status": "Undetermined" + } + } + ], + "issueId": "XRAY-606103", + "references": [ + "https://git.savannah.gnu.org/cgit/wget.git/commit/?id=ed0c7c7e0e8f7298352646b2fd6e06a11e242ace", + "https://lists.gnu.org/archive/html/bug-wget/2024-06/msg00005.html", + "https://security-tracker.debian.org/tracker/CVE-2024-38428" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, { "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", "version": "", "location": { "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" } - } - ], - "summary": "url.c in GNU Wget through 1.24.5 mishandles semicolons in the userinfo subcomponent of a URI, and thus there may be insecure behavior in which data that was supposed to be in the userinfo subcomponent is misinterpreted to be part of the host subcomponent.", - "applicable": "Undetermined", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2024-38428", - "cvssV2": "", - "cvssV3": "9.1", - "applicability": { - "status": "Undetermined" + }, + { + "name": "debian:bookworm:wget", + "version": "1.21.3-1+b1", + "location": { + "file": "wget:1.21.3-1+b1" } } - ], - "issueId": "XRAY-606103", - "references": [ - "https://git.savannah.gnu.org/cgit/wget.git/commit/?id=ed0c7c7e0e8f7298352646b2fd6e06a11e242ace", - "https://lists.gnu.org/archive/html/bug-wget/2024-06/msg00005.html", - "https://security-tracker.debian.org/tracker/CVE-2024-38428" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - { - "name": "debian:bookworm:wget", - "version": "1.21.3-1+b1", - "location": { - "file": "wget:1.21.3-1+b1" - } - } - ] - ], - "jfrogResearchInformation": null - }, - { - "severity": "Critical", - "impactedPackageName": "cors.js", - "impactedPackageVersion": "0.0.1-security", - "impactedPackageType": "npm", - "components": [ + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Critical", + "impactedPackageName": "cors.js", + "impactedPackageVersion": "0.0.1-security", + "impactedPackageType": "npm", + "components": [ + { + "name": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar", + "version": "", + "location": { + "file": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" + } + } + ], + "summary": "Malicious package cors.js for Node.js", + "applicable": "Not Covered", + "fixedVersions": null, + "cves": null, + "issueId": "XRAY-264729", + "references": [ + "https://registry.npmjs.com" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, { "name": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar", "version": "", "location": { "file": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" } + }, + { + "name": "cors.js", + "version": "0.0.1-security", + "location": { + "file": "usr/src/app/node_modules/cors.js/package.json" + } } - ], + ] + ], + "jfrogResearchInformation": { + "severity": "Critical", "summary": "Malicious package cors.js for Node.js", - "applicable": "Not Covered", - "fixedVersions": null, - "cves": null, - "issueId": "XRAY-264729", - "references": [ - "https://registry.npmjs.com" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar", - "version": "", - "location": { - "file": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" - } - }, - { - "name": "cors.js", - "version": "0.0.1-security", - "location": { - "file": "usr/src/app/node_modules/cors.js/package.json" - } - } - ] - ], - "jfrogResearchInformation": { - "severity": "Critical", - "summary": "Malicious package cors.js for Node.js", - "details": "The package cors.js for Node.js contains malicious code that installs a persistent connectback shell. The package is typosquatting the popular `cors` package. When installed, the package opens a connectback shell to the hardcoded host `107.175.32.229` on TCP port 56173. The malicious payload achieves persistency by installing a cron job that repeats every 10 seconds - `*/10 * * * * *`", - "remediation": "As with any malware, the malicious package must be completely removed, and steps must be taken care to remediate the damage that was done by the malicious package -\n\n##### Removing the malicious package\n\nRun `npm uninstall cors.js`\n\n##### Refreshing stolen credentials\n\nMany malicious packages steal stored user credentials, focusing on the following -\n\n* [Browser autocomplete](https://jfrog.com/blog/malicious-pypi-packages-stealing-credit-cards-injecting-code/) data, such as saved passwords and credit cards\n* [Environment variables](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/) passed to the malicious code\n* [Stored Discord tokens](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)\n* AWS / GitHub credentials stored in cleartext files\n\nIt is highly recommended to change or revoke data that is stored in the infected machine at those locations\n\n##### Stopping malicious processes\n\nMany malicious packages start malicious processes such as [connectback shells](https://jfrog.com/blog/jfrog-discloses-3-remote-access-trojans-in-pypi/) or crypto-miners. Search for any unfamiliar processes that consume a large amount of CPU or a large amount of network traffic, and stop them. On Windows, this can be facilitated with [Sysinternals Process Explorer](https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer).\n\n##### Removing installed backdoors\n\nMany malicious packages install themselves as a [persistent backdoor](https://jfrog.com/blog/npm-supply-chain-attack-targets-german-based-companies/), in order to guarantee the malicious code survives a reboot. Search for any unfamiliar binaries set to be run on startup, and remove them. On Windows, this can be facilitated with [Sysinternals Autoruns](https://docs.microsoft.com/en-us/sysinternals/downloads/autoruns).\n\n##### Defining an Xray policy that blocks downloads of Artifacts with malicious packages\n\nIt is possible to [create an Xray policy](https://www.jfrog.com/confluence/display/JFROG/Creating+Xray+Policies+and+Rules) that will not allow artifacts with identified malicious packages to be downloaded from Artifactory. To create such a policy, add a new `Security` policy and set `Minimal Severity` to `Critical`. Under `Automatic Actions` check the `Block Download` action.\n\n##### Contacting the JFrog Security Research team for additional information\n\nOptionally, if you are unsure of the full impact of the malicious package and wish to get more details, the JFrog Security Research team can help you assess the potential damage from the installed malicious package.\n\nPlease contact us at research@jfrog.com with details of the affected artifact and the name of the identified malicious package." + "details": "The package cors.js for Node.js contains malicious code that installs a persistent connectback shell. The package is typosquatting the popular `cors` package. When installed, the package opens a connectback shell to the hardcoded host `107.175.32.229` on TCP port 56173. The malicious payload achieves persistency by installing a cron job that repeats every 10 seconds - `*/10 * * * * *`", + "remediation": "As with any malware, the malicious package must be completely removed, and steps must be taken care to remediate the damage that was done by the malicious package -\n\n##### Removing the malicious package\n\nRun `npm uninstall cors.js`\n\n##### Refreshing stolen credentials\n\nMany malicious packages steal stored user credentials, focusing on the following -\n\n* [Browser autocomplete](https://jfrog.com/blog/malicious-pypi-packages-stealing-credit-cards-injecting-code/) data, such as saved passwords and credit cards\n* [Environment variables](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/) passed to the malicious code\n* [Stored Discord tokens](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)\n* AWS / GitHub credentials stored in cleartext files\n\nIt is highly recommended to change or revoke data that is stored in the infected machine at those locations\n\n##### Stopping malicious processes\n\nMany malicious packages start malicious processes such as [connectback shells](https://jfrog.com/blog/jfrog-discloses-3-remote-access-trojans-in-pypi/) or crypto-miners. Search for any unfamiliar processes that consume a large amount of CPU or a large amount of network traffic, and stop them. On Windows, this can be facilitated with [Sysinternals Process Explorer](https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer).\n\n##### Removing installed backdoors\n\nMany malicious packages install themselves as a [persistent backdoor](https://jfrog.com/blog/npm-supply-chain-attack-targets-german-based-companies/), in order to guarantee the malicious code survives a reboot. Search for any unfamiliar binaries set to be run on startup, and remove them. On Windows, this can be facilitated with [Sysinternals Autoruns](https://docs.microsoft.com/en-us/sysinternals/downloads/autoruns).\n\n##### Defining an Xray policy that blocks downloads of Artifacts with malicious packages\n\nIt is possible to [create an Xray policy](https://www.jfrog.com/confluence/display/JFROG/Creating+Xray+Policies+and+Rules) that will not allow artifacts with identified malicious packages to be downloaded from Artifactory. To create such a policy, add a new `Security` policy and set `Minimal Severity` to `Critical`. Under `Automatic Actions` check the `Block Download` action.\n\n##### Contacting the JFrog Security Research team for additional information\n\nOptionally, if you are unsure of the full impact of the malicious package and wish to get more details, the JFrog Security Research team can help you assess the potential damage from the installed malicious package.\n\nPlease contact us at research@jfrog.com with details of the affected artifact and the name of the identified malicious package." + } + }, + { + "severity": "Low", + "impactedPackageName": "debian:bookworm:openssh-client:1", + "impactedPackageVersion": "9.2p1-2+deb12u3", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } } - }, - { - "severity": "Low", - "impactedPackageName": "debian:bookworm:openssh-client:1", - "impactedPackageVersion": "9.2p1-2+deb12u3", - "impactedPackageType": "Debian", - "components": [ + ], + "summary": "OpenSSH through 9.6, when common types of DRAM are used, might allow row hammer attacks (for authentication bypass) because the integer value of authenticated in mm_answer_authpassword does not resist flips of a single bit. NOTE: this is applicable to a certain threat model of attacker-victim co-location in which the attacker has user privileges.", + "applicable": "Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2023-51767", + "cvssV2": "", + "cvssV3": "7.0", + "applicability": { + "status": "Applicable", + "scannerDescription": "The CVE is always applicable.\n\nNote - The vulnerability is hardware-dependent." + } + } + ], + "issueId": "XRAY-585612", + "references": [ + "https://arxiv.org/abs/2309.02545", + "https://github.com/openssh/openssh-portable/blob/8241b9c0529228b4b86d88b1a6076fb9f97e4a99/monitor.c#L878", + "https://github.com/openssh/openssh-portable/blob/8241b9c0529228b4b86d88b1a6076fb9f97e4a99/auth-passwd.c#L77", + "https://bugzilla.redhat.com/show_bug.cgi?id=2255850", + "https://security-tracker.debian.org/tracker/CVE-2023-51767", + "https://ubuntu.com/security/CVE-2023-51767", + "https://security.netapp.com/advisory/ntap-20240125-0006/", + "https://access.redhat.com/security/cve/CVE-2023-51767" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, { "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", "version": "", "location": { "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" } - } - ], - "summary": "OpenSSH through 9.6, when common types of DRAM are used, might allow row hammer attacks (for authentication bypass) because the integer value of authenticated in mm_answer_authpassword does not resist flips of a single bit. NOTE: this is applicable to a certain threat model of attacker-victim co-location in which the attacker has user privileges.", - "applicable": "Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2023-51767", - "cvssV2": "", - "cvssV3": "7.0", - "applicability": { - "status": "Applicable", - "scannerDescription": "The CVE is always applicable.\n\nNote - The vulnerability is hardware-dependent." + }, + { + "name": "debian:bookworm:openssh-client:1", + "version": "9.2p1-2+deb12u3", + "location": { + "file": "openssh-client:1:9.2p1-2+deb12u3" } } - ], - "issueId": "XRAY-585612", - "references": [ - "https://arxiv.org/abs/2309.02545", - "https://github.com/openssh/openssh-portable/blob/8241b9c0529228b4b86d88b1a6076fb9f97e4a99/monitor.c#L878", - "https://github.com/openssh/openssh-portable/blob/8241b9c0529228b4b86d88b1a6076fb9f97e4a99/auth-passwd.c#L77", - "https://bugzilla.redhat.com/show_bug.cgi?id=2255850", - "https://security-tracker.debian.org/tracker/CVE-2023-51767", - "https://ubuntu.com/security/CVE-2023-51767", - "https://security.netapp.com/advisory/ntap-20240125-0006/", - "https://access.redhat.com/security/cve/CVE-2023-51767" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", - "version": "", - "location": { - "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - }, - { - "name": "debian:bookworm:openssh-client:1", - "version": "9.2p1-2+deb12u3", - "location": { - "file": "openssh-client:1:9.2p1-2+deb12u3" + ] + ], + "jfrogResearchInformation": { + "severity": "Low", + "summary": "The RowHammer fault injection attack can theoretically lead to local authentication bypass in OpenSSH.", + "details": "[OpenSSH](https://www.openssh.com/) is a popular open-source implementation of the SSH (Secure Shell) protocol, providing encrypted communication over a network.\nIt was discovered that the OpenSSH authentication logic can be susceptible in some cases to a side-channel fault injection attack. The attack can theoretically be carried out by a local attacker which eventually bypass OpenSSH authentication mechanism.\n\nThis vulnerability currently lacks widely known published exploits, and its exploitation is considered highly complex. The intricacies of the attack, combined with the absence of well-documented exploits, contribute to the difficulty in achieving successful exploitation. Furthermore, it's essential to note that the susceptibility to this vulnerability is hardware-dependent, and the success of an attack relies on probabilities associated with the specific hardware configuration. \n\nThe vulnerability is theoretically exploitable by several different ways, the only two published ways are:\n\nIn the OpenSSH function `mm_answer_authpassword()`, a stack variable `authenticated`, is assigned to the value of the function `auth_password()` which returns 1/0 and then returned. If the value of `authenticated` is 1, the SSH connection will be established. Since `authenticated` is stored on the stack, therefore in DRAM, a local attacker could flip this 32-bit integer least significant bit, thus, bypass authentication.\n\nAnother possible exploit is the `result` stack variable in `auth_password()` function. It is initialized to 0 and set to 1 if the password is correct. \nSimilarly to the previous method, this attack requires a single bit flip of the `result` variable in order for the function to return 1 and bypass the authentication.\n\nAttackers can trigger the vulnerability via a RowHammer fault injection. The Rowhammer bug is a hardware reliability issue in which an attacker repeatedly accesses (hammers) DRAM cells to cause unauthorized changes in physically adjacent memory locations.\nSimply put:\n\n* A specific register value(`authenticated`/`result` value) is pushed onto the stack during program execution. \n* The stack, where the register value is stored, is identified to be located in a memory row susceptible to bit flips (flippable row) due to the RowHammer vulnerability in DRAM.\n* The attacker performs a series of rapid and repeated memory accesses to the adjacent rows of the flippable row in the DRAM. This repeated access exploits the RowHammer vulnerability, inducing bit flips in the targeted flippable row.\n* Due to the RowHammer effect, bit flips occur in the flippable row, potentially corrupting the data stored there.\n* After inducing bit flips in the flippable row, the attacker manipulates the program's control flow to pop the corrupted value from the stack into a register.\n* The register now holds a value that has been corrupted through the RowHammer attack. Now the `authenticated`/`result` variables hold this corrupted value thus it can lead to authentication bypass, as it may impact the control flow in a way advantageous to the attacker.", + "severityReasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The vulnerability depends on the OS and hardware. It was only evaluated in one test environment, therefore results for other conditions might differ. The attacker must be extremely familiar with the details of the exploited system (ex. know the exact hardware which is running the OS).", + "isPositive": true + }, + { + "name": "The issue can only be exploited by an attacker that can execute code on the vulnerable machine (excluding exceedingly rare circumstances)", + "isPositive": true + }, + { + "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", + "description": "Exploitation is extremely non-trivial (even theoretically), no public exploits have been published.", + "isPositive": true + }, + { + "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", + "description": "The vulnerability's attack complexity is significantly higher than what the CVSS represents.", + "isPositive": true + } + ] + } + }, + { + "severity": "Unknown", + "impactedPackageName": "debian:bookworm:libssl3", + "impactedPackageVersion": "3.0.13-1~deb12u1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "CVE-2024-4741", + "applicable": "Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-4741", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called.", + "evidence": [ + { + "file": "usr/local/bin/node", + "reason": "References to the vulnerable functions were found" } - } - ] - ], - "jfrogResearchInformation": { - "severity": "Low", - "summary": "The RowHammer fault injection attack can theoretically lead to local authentication bypass in OpenSSH.", - "details": "[OpenSSH](https://www.openssh.com/) is a popular open-source implementation of the SSH (Secure Shell) protocol, providing encrypted communication over a network.\nIt was discovered that the OpenSSH authentication logic can be susceptible in some cases to a side-channel fault injection attack. The attack can theoretically be carried out by a local attacker which eventually bypass OpenSSH authentication mechanism.\n\nThis vulnerability currently lacks widely known published exploits, and its exploitation is considered highly complex. The intricacies of the attack, combined with the absence of well-documented exploits, contribute to the difficulty in achieving successful exploitation. Furthermore, it's essential to note that the susceptibility to this vulnerability is hardware-dependent, and the success of an attack relies on probabilities associated with the specific hardware configuration. \n\nThe vulnerability is theoretically exploitable by several different ways, the only two published ways are:\n\nIn the OpenSSH function `mm_answer_authpassword()`, a stack variable `authenticated`, is assigned to the value of the function `auth_password()` which returns 1/0 and then returned. If the value of `authenticated` is 1, the SSH connection will be established. Since `authenticated` is stored on the stack, therefore in DRAM, a local attacker could flip this 32-bit integer least significant bit, thus, bypass authentication.\n\nAnother possible exploit is the `result` stack variable in `auth_password()` function. It is initialized to 0 and set to 1 if the password is correct. \nSimilarly to the previous method, this attack requires a single bit flip of the `result` variable in order for the function to return 1 and bypass the authentication.\n\nAttackers can trigger the vulnerability via a RowHammer fault injection. The Rowhammer bug is a hardware reliability issue in which an attacker repeatedly accesses (hammers) DRAM cells to cause unauthorized changes in physically adjacent memory locations.\nSimply put:\n\n* A specific register value(`authenticated`/`result` value) is pushed onto the stack during program execution. \n* The stack, where the register value is stored, is identified to be located in a memory row susceptible to bit flips (flippable row) due to the RowHammer vulnerability in DRAM.\n* The attacker performs a series of rapid and repeated memory accesses to the adjacent rows of the flippable row in the DRAM. This repeated access exploits the RowHammer vulnerability, inducing bit flips in the targeted flippable row.\n* Due to the RowHammer effect, bit flips occur in the flippable row, potentially corrupting the data stored there.\n* After inducing bit flips in the flippable row, the attacker manipulates the program's control flow to pop the corrupted value from the stack into a register.\n* The register now holds a value that has been corrupted through the RowHammer attack. Now the `authenticated`/`result` variables hold this corrupted value thus it can lead to authentication bypass, as it may impact the control flow in a way advantageous to the attacker.", - "severityReasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The vulnerability depends on the OS and hardware. It was only evaluated in one test environment, therefore results for other conditions might differ. The attacker must be extremely familiar with the details of the exploited system (ex. know the exact hardware which is running the OS).", - "isPositive": true - }, - { - "name": "The issue can only be exploited by an attacker that can execute code on the vulnerable machine (excluding exceedingly rare circumstances)", - "isPositive": true - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Exploitation is extremely non-trivial (even theoretically), no public exploits have been published.", - "isPositive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The vulnerability's attack complexity is significantly higher than what the CVSS represents.", - "isPositive": true - } - ] + ] + } } - }, - { - "severity": "Unknown", - "impactedPackageName": "debian:bookworm:libssl3", - "impactedPackageVersion": "3.0.13-1~deb12u1", - "impactedPackageType": "Debian", - "components": [ + ], + "issueId": "XRAY-603657", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-4741" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, { "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", "version": "", "location": { "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" } - } - ], - "summary": "CVE-2024-4741", - "applicable": "Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2024-4741", - "cvssV2": "", - "cvssV3": "", - "applicability": { - "status": "Applicable", - "scannerDescription": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called.", - "evidence": [ - { - "file": "usr/local/bin/node", - "reason": "References to the vulnerable functions were found" - } - ] + }, + { + "name": "debian:bookworm:libssl3", + "version": "3.0.13-1~deb12u1", + "location": { + "file": "libssl3:3.0.13-1~deb12u1" } } - ], - "issueId": "XRAY-603657", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-4741" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - { - "name": "debian:bookworm:libssl3", - "version": "3.0.13-1~deb12u1", - "location": { - "file": "libssl3:3.0.13-1~deb12u1" + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Unknown", + "impactedPackageName": "debian:bookworm:openssl", + "impactedPackageVersion": "3.0.13-1~deb12u1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "CVE-2024-4741", + "applicable": "Applicable", + "fixedVersions": [ + "[3.0.14-1~deb12u1]" + ], + "cves": [ + { + "id": "CVE-2024-4741", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called.", + "evidence": [ + { + "file": "usr/local/bin/node", + "reason": "References to the vulnerable functions were found" } - } - ] - ], - "jfrogResearchInformation": null - }, - { - "severity": "Unknown", - "impactedPackageName": "debian:bookworm:openssl", - "impactedPackageVersion": "3.0.13-1~deb12u1", - "impactedPackageType": "Debian", - "components": [ + ] + } + } + ], + "issueId": "XRAY-603657", + "references": [ + "https://security-tracker.debian.org/tracker/CVE-2024-4741" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, { "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", "version": "", "location": { "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" } - } - ], - "summary": "CVE-2024-4741", - "applicable": "Applicable", - "fixedVersions": [ - "[3.0.14-1~deb12u1]" - ], - "cves": [ - { - "id": "CVE-2024-4741", - "cvssV2": "", - "cvssV3": "", - "applicability": { - "status": "Applicable", - "scannerDescription": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called.", - "evidence": [ - { - "file": "usr/local/bin/node", - "reason": "References to the vulnerable functions were found" - } - ] + }, + { + "name": "debian:bookworm:openssl", + "version": "3.0.13-1~deb12u1", + "location": { + "file": "openssl:3.0.13-1~deb12u1" } } - ], - "issueId": "XRAY-603657", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-4741" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - { - "name": "debian:bookworm:openssl", - "version": "3.0.13-1~deb12u1", - "location": { - "file": "openssl:3.0.13-1~deb12u1" + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Unknown", + "impactedPackageName": "debian:bookworm:libssl3", + "impactedPackageVersion": "3.0.13-1~deb12u1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", + "applicable": "Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-6119", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`", + "evidence": [ + { + "file": "usr/local/bin/node", + "reason": "References to the vulnerable functions were found" } - } - ] - ], - "jfrogResearchInformation": null - }, - { - "severity": "Unknown", - "impactedPackageName": "debian:bookworm:libssl3", - "impactedPackageVersion": "3.0.13-1~deb12u1", - "impactedPackageType": "Debian", - "components": [ + ] + } + } + ], + "issueId": "XRAY-632747", + "references": [ + "https://openssl-library.org/news/secadv/20240903.txt", + "https://github.com/openssl/openssl/commit/621f3729831b05ee828a3203eddb621d014ff2b2", + "https://github.com/openssl/openssl/commit/05f360d9e849a1b277db628f1f13083a7f8dd04f", + "https://security-tracker.debian.org/tracker/CVE-2024-6119", + "https://github.com/openssl/openssl/commit/7dfcee2cd2a63b2c64b9b4b0850be64cb695b0a0", + "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, { "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", "version": "", "location": { "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" } - } - ], - "summary": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", - "applicable": "Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2024-6119", - "cvssV2": "", - "cvssV3": "", - "applicability": { - "status": "Applicable", - "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`", - "evidence": [ - { - "file": "usr/local/bin/node", - "reason": "References to the vulnerable functions were found" - } - ] + }, + { + "name": "debian:bookworm:libssl3", + "version": "3.0.13-1~deb12u1", + "location": { + "file": "libssl3:3.0.13-1~deb12u1" } } - ], - "issueId": "XRAY-632747", - "references": [ - "https://openssl-library.org/news/secadv/20240903.txt", - "https://github.com/openssl/openssl/commit/621f3729831b05ee828a3203eddb621d014ff2b2", - "https://github.com/openssl/openssl/commit/05f360d9e849a1b277db628f1f13083a7f8dd04f", - "https://security-tracker.debian.org/tracker/CVE-2024-6119", - "https://github.com/openssl/openssl/commit/7dfcee2cd2a63b2c64b9b4b0850be64cb695b0a0", - "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - { - "name": "debian:bookworm:libssl3", - "version": "3.0.13-1~deb12u1", - "location": { - "file": "libssl3:3.0.13-1~deb12u1" + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Out of bounds read in OpenSSL clients can lead to denial of service when using non-default TLS verification options and connecting to malicious TLS servers", + "severityReasons": [ + { + "name": "The issue has an exploit published", + "description": "The fix commit contains PoC certificates that trigger the denial of service issue" + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker must make the victim client connect to their malicious TLS server, in order to serve the malformed TLS certificate. The victim client must use OpenSSL and must enable non-default certificate verification options, either -\n\n* DNS verification - by using `X509_VERIFY_PARAM_set1_host` or `X509_check_host`\n* Email verification - by using ` X509_VERIFY_PARAM_set1_email` or `X509_check_email`", + "isPositive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Denial of service of a TLS clients only. This out of bounds read cannot lead to data disclosure.", + "isPositive": true + } + ] + } + }, + { + "severity": "Unknown", + "impactedPackageName": "debian:bookworm:openssl", + "impactedPackageVersion": "3.0.13-1~deb12u1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", + "version": "", + "location": { + "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" + } + } + ], + "summary": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", + "applicable": "Applicable", + "fixedVersions": [ + "[3.0.14-1~deb12u2]" + ], + "cves": [ + { + "id": "CVE-2024-6119", + "cvssV2": "", + "cvssV3": "", + "applicability": { + "status": "Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`", + "evidence": [ + { + "file": "usr/local/bin/node", + "reason": "References to the vulnerable functions were found" } - } - ] - ], - "jfrogResearchInformation": { - "severity": "Medium", - "summary": "Out of bounds read in OpenSSL clients can lead to denial of service when using non-default TLS verification options and connecting to malicious TLS servers", - "severityReasons": [ - { - "name": "The issue has an exploit published", - "description": "The fix commit contains PoC certificates that trigger the denial of service issue" - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "The attacker must make the victim client connect to their malicious TLS server, in order to serve the malformed TLS certificate. The victim client must use OpenSSL and must enable non-default certificate verification options, either -\n\n* DNS verification - by using `X509_VERIFY_PARAM_set1_host` or `X509_check_host`\n* Email verification - by using ` X509_VERIFY_PARAM_set1_email` or `X509_check_email`", - "isPositive": true - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "Denial of service of a TLS clients only. This out of bounds read cannot lead to data disclosure.", - "isPositive": true - } - ] + ] + } } - }, - { - "severity": "Unknown", - "impactedPackageName": "debian:bookworm:openssl", - "impactedPackageVersion": "3.0.13-1~deb12u1", - "impactedPackageType": "Debian", - "components": [ + ], + "issueId": "XRAY-632747", + "references": [ + "https://openssl-library.org/news/secadv/20240903.txt", + "https://github.com/openssl/openssl/commit/621f3729831b05ee828a3203eddb621d014ff2b2", + "https://github.com/openssl/openssl/commit/05f360d9e849a1b277db628f1f13083a7f8dd04f", + "https://security-tracker.debian.org/tracker/CVE-2024-6119", + "https://github.com/openssl/openssl/commit/7dfcee2cd2a63b2c64b9b4b0850be64cb695b0a0", + "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, { "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", "version": "", "location": { "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" } - } - ], - "summary": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", - "applicable": "Applicable", - "fixedVersions": [ - "[3.0.14-1~deb12u2]" - ], - "cves": [ - { - "id": "CVE-2024-6119", - "cvssV2": "", - "cvssV3": "", - "applicability": { - "status": "Applicable", - "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`", - "evidence": [ - { - "file": "usr/local/bin/node", - "reason": "References to the vulnerable functions were found" - } - ] + }, + { + "name": "debian:bookworm:openssl", + "version": "3.0.13-1~deb12u1", + "location": { + "file": "openssl:3.0.13-1~deb12u1" } } - ], - "issueId": "XRAY-632747", - "references": [ - "https://openssl-library.org/news/secadv/20240903.txt", - "https://github.com/openssl/openssl/commit/621f3729831b05ee828a3203eddb621d014ff2b2", - "https://github.com/openssl/openssl/commit/05f360d9e849a1b277db628f1f13083a7f8dd04f", - "https://security-tracker.debian.org/tracker/CVE-2024-6119", - "https://github.com/openssl/openssl/commit/7dfcee2cd2a63b2c64b9b4b0850be64cb695b0a0", - "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - { - "name": "debian:bookworm:openssl", - "version": "3.0.13-1~deb12u1", - "location": { - "file": "openssl:3.0.13-1~deb12u1" - } - } - ] - ], - "jfrogResearchInformation": { - "severity": "Medium", - "summary": "Out of bounds read in OpenSSL clients can lead to denial of service when using non-default TLS verification options and connecting to malicious TLS servers", - "severityReasons": [ - { - "name": "The issue has an exploit published", - "description": "The fix commit contains PoC certificates that trigger the denial of service issue" - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "The attacker must make the victim client connect to their malicious TLS server, in order to serve the malformed TLS certificate. The victim client must use OpenSSL and must enable non-default certificate verification options, either -\n\n* DNS verification - by using `X509_VERIFY_PARAM_set1_host` or `X509_check_host`\n* Email verification - by using ` X509_VERIFY_PARAM_set1_email` or `X509_check_email`", - "isPositive": true - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "Denial of service of a TLS clients only. This out of bounds read cannot lead to data disclosure.", - "isPositive": true - } - ] + ] + ], + "jfrogResearchInformation": { + "severity": "Medium", + "summary": "Out of bounds read in OpenSSL clients can lead to denial of service when using non-default TLS verification options and connecting to malicious TLS servers", + "severityReasons": [ + { + "name": "The issue has an exploit published", + "description": "The fix commit contains PoC certificates that trigger the denial of service issue" + }, + { + "name": "The prerequisites for exploiting the issue are extremely unlikely", + "description": "The attacker must make the victim client connect to their malicious TLS server, in order to serve the malformed TLS certificate. The victim client must use OpenSSL and must enable non-default certificate verification options, either -\n\n* DNS verification - by using `X509_VERIFY_PARAM_set1_host` or `X509_check_host`\n* Email verification - by using ` X509_VERIFY_PARAM_set1_email` or `X509_check_email`", + "isPositive": true + }, + { + "name": "The issue cannot result in a severe impact (such as remote code execution)", + "description": "Denial of service of a TLS clients only. This out of bounds read cannot lead to data disclosure.", + "isPositive": true + } + ] + } + }, + { + "severity": "Critical", + "impactedPackageName": "debian:bookworm:libexpat1", + "impactedPackageVersion": "2.5.0-1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } } - }, - { - "severity": "Critical", - "impactedPackageName": "debian:bookworm:libexpat1", - "impactedPackageVersion": "2.5.0-1", - "impactedPackageType": "Debian", - "components": [ + ], + "summary": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", + "applicable": "Not Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-45490", + "cvssV2": "", + "cvssV3": "9.8", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `XML_Parse()`\n- `XML_ParseBuffer()`\n\nAn additional condition, which the scanner currently does not check, is that the `len` parameter which is passed to those functions is user-controlled." + } + } + ], + "issueId": "XRAY-632613", + "references": [ + "https://github.com/libexpat/libexpat/issues/887", + "https://security-tracker.debian.org/tracker/CVE-2024-45490", + "https://github.com/libexpat/libexpat/pull/890" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, { "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", "version": "", "location": { "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" } - } - ], - "summary": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", - "applicable": "Not Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2024-45490", - "cvssV2": "", - "cvssV3": "9.8", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `XML_Parse()`\n- `XML_ParseBuffer()`\n\nAn additional condition, which the scanner currently does not check, is that the `len` parameter which is passed to those functions is user-controlled." + }, + { + "name": "debian:bookworm:libexpat1", + "version": "2.5.0-1", + "location": { + "file": "libexpat1:2.5.0-1" } } - ], - "issueId": "XRAY-632613", - "references": [ - "https://github.com/libexpat/libexpat/issues/887", - "https://security-tracker.debian.org/tracker/CVE-2024-45490", - "https://github.com/libexpat/libexpat/pull/890" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", - "version": "", - "location": { - "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - }, - { - "name": "debian:bookworm:libexpat1", - "version": "2.5.0-1", - "location": { - "file": "libexpat1:2.5.0-1" - } - } - ] - ], - "jfrogResearchInformation": null - }, - { - "severity": "Critical", - "impactedPackageName": "debian:bookworm:libexpat1", - "impactedPackageVersion": "2.5.0-1", - "impactedPackageType": "Debian", - "components": [ + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Critical", + "impactedPackageName": "debian:bookworm:libexpat1", + "impactedPackageVersion": "2.5.0-1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", + "version": "", + "location": { + "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" + } + } + ], + "summary": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", + "applicable": "Not Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2024-45492", + "cvssV2": "", + "cvssV3": "9.8", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks whether the current binary was compiled with 32-bit architecture and if any of the vulnerable functions are called:\n\n- `XML_ParseBuffer()`\n- `XML_Parse()`\n\nNote - the vulnerability occurs when certain inputs are passed to those functions." + } + } + ], + "issueId": "XRAY-632612", + "references": [ + "https://github.com/libexpat/libexpat/issues/889", + "https://security-tracker.debian.org/tracker/CVE-2024-45492", + "https://github.com/libexpat/libexpat/pull/892" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, { "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", "version": "", "location": { "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" } - } - ], - "summary": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", - "applicable": "Not Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2024-45492", - "cvssV2": "", - "cvssV3": "9.8", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether the current binary was compiled with 32-bit architecture and if any of the vulnerable functions are called:\n\n- `XML_ParseBuffer()`\n- `XML_Parse()`\n\nNote - the vulnerability occurs when certain inputs are passed to those functions." + }, + { + "name": "debian:bookworm:libexpat1", + "version": "2.5.0-1", + "location": { + "file": "libexpat1:2.5.0-1" } } - ], - "issueId": "XRAY-632612", - "references": [ - "https://github.com/libexpat/libexpat/issues/889", - "https://security-tracker.debian.org/tracker/CVE-2024-45492", - "https://github.com/libexpat/libexpat/pull/892" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", - "version": "", - "location": { - "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - }, - { - "name": "debian:bookworm:libexpat1", - "version": "2.5.0-1", - "location": { - "file": "libexpat1:2.5.0-1" - } - } - ] - ], - "jfrogResearchInformation": null - }, - { - "severity": "Low", - "impactedPackageName": "debian:bookworm:libapt-pkg6.0", - "impactedPackageVersion": "2.6.1", - "impactedPackageType": "Debian", - "components": [ + ] + ], + "jfrogResearchInformation": null + }, + { + "severity": "Low", + "impactedPackageName": "debian:bookworm:apt", + "impactedPackageVersion": "2.6.1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", + "version": "", + "location": { + "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } + } + ], + "summary": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", + "applicable": "Not Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2011-3374", + "cvssV2": "4.3", + "cvssV3": "3.7", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." + } + } + ], + "issueId": "XRAY-34417", + "references": [ + "https://people.canonical.com/~ubuntu-security/cve/2011/CVE-2011-3374.html", + "https://seclists.org/fulldisclosure/2011/Sep/221", + "https://ubuntu.com/security/CVE-2011-3374", + "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=642480", + "https://access.redhat.com/security/cve/cve-2011-3374", + "https://snyk.io/vuln/SNYK-LINUX-APT-116518", + "https://security-tracker.debian.org/tracker/CVE-2011-3374" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, { "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", "version": "", "location": { "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" } - } - ], - "summary": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", - "applicable": "Not Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2011-3374", - "cvssV2": "4.3", - "cvssV3": "3.7", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." + }, + { + "name": "debian:bookworm:apt", + "version": "2.6.1", + "location": { + "file": "apt:2.6.1" } } + ] + ], + "jfrogResearchInformation": { + "severity": "High", + "summary": "Improper signature validation in apt-key may enable Man-in-the-Middle attacks and result in code execution.", + "details": "`apt-key` is [`apt`](https://github.com/Debian/apt)'s key management utility, and is used to manage the keys that are used by `apt` to authenticate packages.\n\nA vulnerability in `apt-key`'s `net-update` function exists, in which [`GPG`](https://www.gnupg.org/) keys, that are used for signing packages and validating their authenticity, aren't validated correctly. The `net-update` function pulls the signing keys that should be added from an insecure location (`http://...`), exposing it to a Man-in-the-Middle attack in which malicious signing keys could be added to the system's keyring. This issue happens due to a vulnerability in the `add_keys_with_veirfy_against_master_keyring()` function, which allows adding signing keys without proper signature validation. \n\nThis vulnerability then potentially allows a malicious actor to perform a Man-in-the-Middle attack on a target, by making it validate malicious packages that were signed with the `GPG` signing key used by the attacker. Effectively, this means that `apt` can be duped to install malicious services and daemons with root privileges.\n\nThe conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man In The Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from [python-apt](https://pypi.org/project/python-apt/) Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.\n\nDo note that `apt-key` is **deprecated** and shouldn't be used, and in most Debian versions `ARCHIVE_KEYRING_URI` is not defined, making this vulnerability unexploitable in most Debian systems.", + "severityReasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the python-apt Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", + "isPositive": true + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "This vulnerability is remotely exploitable when the applicability conditions apply." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Remote code execution is possible when the applicability conditions apply." + }, + { + "name": "The issue has an exploit published", + "description": "The reporter of this issue has provided a GPG key that can be used for an actual attack, as well as a simple PoC example." + } ], - "issueId": "XRAY-34417", - "references": [ - "https://people.canonical.com/~ubuntu-security/cve/2011/CVE-2011-3374.html", - "https://seclists.org/fulldisclosure/2011/Sep/221", - "https://ubuntu.com/security/CVE-2011-3374", - "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=642480", - "https://access.redhat.com/security/cve/cve-2011-3374", - "https://snyk.io/vuln/SNYK-LINUX-APT-116518", - "https://security-tracker.debian.org/tracker/CVE-2011-3374" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", - "version": "", - "location": { - "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" - } - }, - { - "name": "debian:bookworm:libapt-pkg6.0", - "version": "2.6.1", - "location": { - "file": "libapt-pkg6.0:2.6.1" - } - } - ] - ], - "jfrogResearchInformation": { - "severity": "High", - "summary": "Improper signature validation in apt-key may enable Man-in-the-Middle attacks and result in code execution.", - "details": "`apt-key` is [`apt`](https://github.com/Debian/apt)'s key management utility, and is used to manage the keys that are used by `apt` to authenticate packages.\n\nA vulnerability in `apt-key`'s `net-update` function exists, in which [`GPG`](https://www.gnupg.org/) keys, that are used for signing packages and validating their authenticity, aren't validated correctly. The `net-update` function pulls the signing keys that should be added from an insecure location (`http://...`), exposing it to a Man-in-the-Middle attack in which malicious signing keys could be added to the system's keyring. This issue happens due to a vulnerability in the `add_keys_with_veirfy_against_master_keyring()` function, which allows adding signing keys without proper signature validation. \n\nThis vulnerability then potentially allows a malicious actor to perform a Man-in-the-Middle attack on a target, by making it validate malicious packages that were signed with the `GPG` signing key used by the attacker. Effectively, this means that `apt` can be duped to install malicious services and daemons with root privileges.\n\nThe conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man In The Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from [python-apt](https://pypi.org/project/python-apt/) Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.\n\nDo note that `apt-key` is **deprecated** and shouldn't be used, and in most Debian versions `ARCHIVE_KEYRING_URI` is not defined, making this vulnerability unexploitable in most Debian systems.", - "severityReasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the python-apt Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", - "isPositive": true - }, - { - "name": "The issue can be exploited by attackers over the network", - "description": "This vulnerability is remotely exploitable when the applicability conditions apply." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Remote code execution is possible when the applicability conditions apply." - }, - { - "name": "The issue has an exploit published", - "description": "The reporter of this issue has provided a GPG key that can be used for an actual attack, as well as a simple PoC example." - } - ], - "remediation": "##### Deployment mitigations\n\n* Dot not execute `apt-key` command, as it is deprecated.\n* Remove the URI configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`." + "remediation": "##### Deployment mitigations\n\n* Dot not execute `apt-key` command, as it is deprecated.\n* Remove the URI configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`." + } + }, + { + "severity": "Low", + "impactedPackageName": "debian:bookworm:libapt-pkg6.0", + "impactedPackageVersion": "2.6.1", + "impactedPackageType": "Debian", + "components": [ + { + "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", + "version": "", + "location": { + "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" + } } - }, - { - "severity": "Low", - "impactedPackageName": "debian:bookworm:apt", - "impactedPackageVersion": "2.6.1", - "impactedPackageType": "Debian", - "components": [ + ], + "summary": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", + "applicable": "Not Applicable", + "fixedVersions": null, + "cves": [ + { + "id": "CVE-2011-3374", + "cvssV2": "4.3", + "cvssV3": "3.7", + "applicability": { + "status": "Not Applicable", + "scannerDescription": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." + } + } + ], + "issueId": "XRAY-34417", + "references": [ + "https://people.canonical.com/~ubuntu-security/cve/2011/CVE-2011-3374.html", + "https://seclists.org/fulldisclosure/2011/Sep/221", + "https://ubuntu.com/security/CVE-2011-3374", + "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=642480", + "https://access.redhat.com/security/cve/cve-2011-3374", + "https://snyk.io/vuln/SNYK-LINUX-APT-116518", + "https://security-tracker.debian.org/tracker/CVE-2011-3374" + ], + "impactPaths": [ + [ + { + "name": "platform.jfrog.io/swamp-docker/swamp", + "version": "latest" + }, { "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", "version": "", "location": { "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" } - } - ], - "summary": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", - "applicable": "Not Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2011-3374", - "cvssV2": "4.3", - "cvssV3": "3.7", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." + }, + { + "name": "debian:bookworm:libapt-pkg6.0", + "version": "2.6.1", + "location": { + "file": "libapt-pkg6.0:2.6.1" } } + ] + ], + "jfrogResearchInformation": { + "severity": "High", + "summary": "Improper signature validation in apt-key may enable Man-in-the-Middle attacks and result in code execution.", + "details": "`apt-key` is [`apt`](https://github.com/Debian/apt)'s key management utility, and is used to manage the keys that are used by `apt` to authenticate packages.\n\nA vulnerability in `apt-key`'s `net-update` function exists, in which [`GPG`](https://www.gnupg.org/) keys, that are used for signing packages and validating their authenticity, aren't validated correctly. The `net-update` function pulls the signing keys that should be added from an insecure location (`http://...`), exposing it to a Man-in-the-Middle attack in which malicious signing keys could be added to the system's keyring. This issue happens due to a vulnerability in the `add_keys_with_veirfy_against_master_keyring()` function, which allows adding signing keys without proper signature validation. \n\nThis vulnerability then potentially allows a malicious actor to perform a Man-in-the-Middle attack on a target, by making it validate malicious packages that were signed with the `GPG` signing key used by the attacker. Effectively, this means that `apt` can be duped to install malicious services and daemons with root privileges.\n\nThe conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man In The Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from [python-apt](https://pypi.org/project/python-apt/) Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.\n\nDo note that `apt-key` is **deprecated** and shouldn't be used, and in most Debian versions `ARCHIVE_KEYRING_URI` is not defined, making this vulnerability unexploitable in most Debian systems.", + "severityReasons": [ + { + "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", + "description": "The conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the python-apt Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", + "isPositive": true + }, + { + "name": "The issue can be exploited by attackers over the network", + "description": "This vulnerability is remotely exploitable when the applicability conditions apply." + }, + { + "name": "The issue results in a severe impact (such as remote code execution)", + "description": "Remote code execution is possible when the applicability conditions apply." + }, + { + "name": "The issue has an exploit published", + "description": "The reporter of this issue has provided a GPG key that can be used for an actual attack, as well as a simple PoC example." + } ], - "issueId": "XRAY-34417", - "references": [ - "https://people.canonical.com/~ubuntu-security/cve/2011/CVE-2011-3374.html", - "https://seclists.org/fulldisclosure/2011/Sep/221", - "https://ubuntu.com/security/CVE-2011-3374", - "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=642480", - "https://access.redhat.com/security/cve/cve-2011-3374", - "https://snyk.io/vuln/SNYK-LINUX-APT-116518", - "https://security-tracker.debian.org/tracker/CVE-2011-3374" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", - "version": "", - "location": { - "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" - } - }, - { - "name": "debian:bookworm:apt", - "version": "2.6.1", - "location": { - "file": "apt:2.6.1" - } - } - ] - ], - "jfrogResearchInformation": { - "severity": "High", - "summary": "Improper signature validation in apt-key may enable Man-in-the-Middle attacks and result in code execution.", - "details": "`apt-key` is [`apt`](https://github.com/Debian/apt)'s key management utility, and is used to manage the keys that are used by `apt` to authenticate packages.\n\nA vulnerability in `apt-key`'s `net-update` function exists, in which [`GPG`](https://www.gnupg.org/) keys, that are used for signing packages and validating their authenticity, aren't validated correctly. The `net-update` function pulls the signing keys that should be added from an insecure location (`http://...`), exposing it to a Man-in-the-Middle attack in which malicious signing keys could be added to the system's keyring. This issue happens due to a vulnerability in the `add_keys_with_veirfy_against_master_keyring()` function, which allows adding signing keys without proper signature validation. \n\nThis vulnerability then potentially allows a malicious actor to perform a Man-in-the-Middle attack on a target, by making it validate malicious packages that were signed with the `GPG` signing key used by the attacker. Effectively, this means that `apt` can be duped to install malicious services and daemons with root privileges.\n\nThe conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man In The Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from [python-apt](https://pypi.org/project/python-apt/) Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.\n\nDo note that `apt-key` is **deprecated** and shouldn't be used, and in most Debian versions `ARCHIVE_KEYRING_URI` is not defined, making this vulnerability unexploitable in most Debian systems.", - "severityReasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the python-apt Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", - "isPositive": true - }, - { - "name": "The issue can be exploited by attackers over the network", - "description": "This vulnerability is remotely exploitable when the applicability conditions apply." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Remote code execution is possible when the applicability conditions apply." - }, - { - "name": "The issue has an exploit published", - "description": "The reporter of this issue has provided a GPG key that can be used for an actual attack, as well as a simple PoC example." - } - ], - "remediation": "##### Deployment mitigations\n\n* Dot not execute `apt-key` command, as it is deprecated.\n* Remove the URI configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`." - } - } - ], - "securityViolations": null, - "licensesViolations": null, - "licenses": null, - "operationalRiskViolations": null, - "secrets": [ - { - "severity": "Medium", - "file": "usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc", - "snippet": "htt************", - "finding": "Hardcoded secrets were found", - "scannerDescription": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - { - "severity": "Medium", - "file": "private/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/tmpsfyn_3d1/unpacked/filesystem/blobs/sha256/9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0/usr/src/app/server/index.js", - "startLine": 5, - "startColumn": 7, - "endLine": 5, - "endColumn": 57, - "snippet": "tok************", - "finding": "Hardcoded secrets were found", - "scannerDescription": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - { - "severity": "Medium", - "file": "private/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/tmpsfyn_3d1/unpacked/filesystem/blobs/sha256/9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0/usr/src/app/server/index.js", - "startLine": 6, - "startColumn": 14, - "endLine": 6, - "endColumn": 24, - "snippet": "eyJ************", - "finding": "Secret keys were found", - "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops\u0026tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + "remediation": "##### Deployment mitigations\n\n* Dot not execute `apt-key` command, as it is deprecated.\n* Remove the URI configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`." } - ], - "iacViolations": null, - "sastViolations": null, - "errors": null - } \ No newline at end of file + } + ], + "securityViolations": null, + "licensesViolations": null, + "licenses": null, + "operationalRiskViolations": null, + "secrets": [ + { + "severity": "Medium", + "file": "usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc", + "snippet": "htt************", + "finding": "Hardcoded secrets were found", + "scannerDescription": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + { + "severity": "Medium", + "file": "private/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/tmpsfyn_3d1/unpacked/filesystem/blobs/sha256/9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0/usr/src/app/server/index.js", + "startLine": 5, + "startColumn": 7, + "endLine": 5, + "endColumn": 57, + "snippet": "tok************", + "finding": "Hardcoded secrets were found", + "scannerDescription": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" + }, + { + "severity": "Medium", + "file": "private/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/tmpsfyn_3d1/unpacked/filesystem/blobs/sha256/9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0/usr/src/app/server/index.js", + "startLine": 6, + "startColumn": 14, + "endLine": 6, + "endColumn": 24, + "snippet": "eyJ************", + "finding": "Secret keys were found", + "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" + } + ], + "iacViolations": null, + "sastViolations": null, + "errors": null +} diff --git a/utils/formats/sarifutils/test_sarifutils.go b/utils/formats/sarifutils/test_sarifutils.go index b3b589d5..78cac692 100644 --- a/utils/formats/sarifutils/test_sarifutils.go +++ b/utils/formats/sarifutils/test_sarifutils.go @@ -43,6 +43,7 @@ func CreateRunWithDummyResultAndRuleProperties(result *sarif.Result, properties, if rule == nil { return nil } + rule.Properties = map[string]interface{}{} for index := range properties { rule.Properties[properties[index]] = values[index] } diff --git a/utils/results/conversion/convertor_test.go b/utils/results/conversion/convertor_test.go index 94a25c91..3aa560a4 100644 --- a/utils/results/conversion/convertor_test.go +++ b/utils/results/conversion/convertor_test.go @@ -2,12 +2,12 @@ package conversion import ( "fmt" + "os" "path/filepath" "testing" "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/formats" - "github.com/jfrog/jfrog-client-go/utils/log" testUtils "github.com/jfrog/jfrog-cli-security/tests/utils" "github.com/jfrog/jfrog-cli-security/utils/results" @@ -135,7 +135,7 @@ func validateSimpleJsonConversion(t *testing.T, expectedResults formats.SimpleJs return } validationParams.Actual = actualResults - + validations.ValidateCommandSimpleJsonOutput(t, validationParams) } @@ -148,10 +148,6 @@ func validateSarifConversion(t *testing.T, expectedResults *sarif.Report, inputR } validationParams.Actual = actualResults - marshAct, err := utils.GetAsJsonString(actualResults, false, true) - assert.NoError(t, err) - log.Output(marshAct) - validations.ValidateCommandSarifOutput(t, validationParams) } diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go index 04a24886..c1f30b3b 100644 --- a/utils/results/conversion/simplejsonparser/simplejsonparser_test.go +++ b/utils/results/conversion/simplejsonparser/simplejsonparser_test.go @@ -288,7 +288,7 @@ func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { IssueId: "XRAY-1", Cves: []formats.CveRow{{Id: "CVE-1"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 15}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 18}, ImpactedDependencyName: "component-A", // Direct Components: []formats.ComponentRow{{ @@ -303,7 +303,7 @@ func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { IssueId: "XRAY-1", Cves: []formats.CveRow{{Id: "CVE-1"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 15}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 18}, ImpactedDependencyName: "component-B", // Direct Components: []formats.ComponentRow{{ @@ -318,7 +318,7 @@ func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { IssueId: "XRAY-2", Cves: []formats.CveRow{{Id: "CVE-2"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 9}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 10}, ImpactedDependencyName: "component-B", // Direct Components: []formats.ComponentRow{{ @@ -393,7 +393,7 @@ func TestPrepareSimpleJsonVulnerabilities(t *testing.T) { }, }}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 11}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 13}, ImpactedDependencyName: "component-B", // Direct Components: []formats.ComponentRow{{ @@ -441,7 +441,7 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { IssueId: "XRAY-1", Cves: []formats.CveRow{{Id: "CVE-1"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 15}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 18}, ImpactedDependencyName: "component-A", // Direct Components: []formats.ComponentRow{{ @@ -456,7 +456,7 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { IssueId: "XRAY-1", Cves: []formats.CveRow{{Id: "CVE-1"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 15}, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 18}, ImpactedDependencyName: "component-B", // Direct Components: []formats.ComponentRow{{ @@ -471,7 +471,7 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { IssueId: "XRAY-2", Cves: []formats.CveRow{{Id: "CVE-2"}}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 9}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 10}, ImpactedDependencyName: "component-B", // Direct Components: []formats.ComponentRow{{ @@ -486,7 +486,7 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { { LicenseKey: "license-1", ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 9}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 10}, ImpactedDependencyName: "component-B", Components: []formats.ComponentRow{{Name: "component-B", Location: &formats.Location{File: "target"}}}, }, @@ -556,7 +556,7 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { }, }}, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 11}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 13}, ImpactedDependencyName: "component-B", // Direct Components: []formats.ComponentRow{{ @@ -571,7 +571,7 @@ func TestPrepareSimpleJsonViolations(t *testing.T) { { LicenseKey: "license-1", ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ - SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 9}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 10}, ImpactedDependencyName: "component-B", // Direct Components: []formats.ComponentRow{{ @@ -682,7 +682,7 @@ func TestPrepareSimpleJsonJasIssues(t *testing.T) { expectedOutput: []formats.SourceCodeRow{ { Location: formats.Location{File: "file", StartLine: 1, StartColumn: 2, EndLine: 3, EndColumn: 4, Snippet: "secret-snippet"}, - SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 11}, + SeverityDetails: formats.SeverityDetails{Severity: "Low", SeverityNumValue: 13}, }, }, }, From 7ac59492d971000d6baa009cf34467a722465ffe Mon Sep 17 00:00:00 2001 From: attiasas Date: Wed, 25 Sep 2024 18:51:50 +0300 Subject: [PATCH 64/82] continue --- utils/results/conversion/convertor_test.go | 21 ++++++++++++------- .../conversion/sarifparser/sarifparser.go | 4 ++-- .../sarifparser/sarifparser_test.go | 2 +- utils/validations/test_validate_sarif.go | 1 + .../validations/test_validate_simple_json.go | 3 ++- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/utils/results/conversion/convertor_test.go b/utils/results/conversion/convertor_test.go index 3aa560a4..ae247d27 100644 --- a/utils/results/conversion/convertor_test.go +++ b/utils/results/conversion/convertor_test.go @@ -2,7 +2,6 @@ package conversion import ( "fmt" - "os" "path/filepath" "testing" @@ -47,13 +46,21 @@ func getAuditValidationParams() validations.ValidationParams { func getDockerScanValidationParams(unique bool) validations.ValidationParams { params := validations.ValidationParams{ ExactResultsMatch: true, - Vulnerabilities: 11, - Applicable: 3, - NotApplicable: 3, - NotCovered: 1, - Undetermined: 1, Secrets: 3, } + if unique { + params.Vulnerabilities = 11 + params.Applicable = 3 + params.NotApplicable = 3 + params.NotCovered = 1 + params.Undetermined = 1 + } else { + params.Vulnerabilities = 14 + params.Applicable = 5 + params.NotApplicable = 4 + params.NotCovered = 1 + params.Undetermined = 1 + } return params } @@ -135,7 +142,7 @@ func validateSimpleJsonConversion(t *testing.T, expectedResults formats.SimpleJs return } validationParams.Actual = actualResults - + validations.ValidateCommandSimpleJsonOutput(t, validationParams) } diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index a648e1c4..33e70919 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -34,7 +34,7 @@ const ( maxPossibleCve = 10.0 // #nosec G101 -- Not credentials. - binarySecretScannerToolName = "JFrog Binary Secrets Scanner" + BinarySecretScannerToolName = "JFrog Binary Secrets Scanner" ScaScannerToolName = "JFrog Xray Scanner" ) @@ -424,7 +424,7 @@ func patchRunsToPassIngestionRules(cmdType utils.CommandType, subScanType utils. patched := sarifutils.CopyRunMetadata(run) if cmdType.IsTargetBinary() && subScanType == utils.SecretsScan { // Patch the tool name in case of binary scan - sarifutils.SetRunToolName(binarySecretScannerToolName, patched) + sarifutils.SetRunToolName(BinarySecretScannerToolName, patched) } if patched.Tool.Driver != nil { patched.Tool.Driver.Rules = patchRules(cmdType, subScanType, run.Tool.Driver.Rules...) diff --git a/utils/results/conversion/sarifparser/sarifparser_test.go b/utils/results/conversion/sarifparser/sarifparser_test.go index e98a5f9f..6cc29dd2 100644 --- a/utils/results/conversion/sarifparser/sarifparser_test.go +++ b/utils/results/conversion/sarifparser/sarifparser_test.go @@ -404,7 +404,7 @@ func TestPatchRunsToPassIngestionRules(t *testing.T) { expectedResults: []*sarif.Run{ { Tool: sarif.Tool{ - Driver: sarifutils.CreateDummyDriver(binarySecretScannerToolName, &sarif.ReportingDescriptor{ + Driver: sarifutils.CreateDummyDriver(BinarySecretScannerToolName, &sarif.ReportingDescriptor{ ID: "rule", ShortDescription: sarif.NewMultiformatMessageString("[Secret in Binary found] "), }), diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index f6b8968d..aab6425f 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -47,6 +47,7 @@ func ValidateSarifIssuesCount(t *testing.T, params ValidationParams, report *sar iac := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(report, IacToolName)...) vulnerabilities += iac secrets := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(report, SecretsToolName)...) + secrets += sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(report, sarifparser.BinarySecretScannerToolName)...) vulnerabilities += secrets sast := sarifutils.GetResultsLocationCount(sarifutils.GetRunsByToolName(report, SastToolName)...) vulnerabilities += sast diff --git a/utils/validations/test_validate_simple_json.go b/utils/validations/test_validate_simple_json.go index 16b42cf1..908ebe29 100644 --- a/utils/validations/test_validate_simple_json.go +++ b/utils/validations/test_validate_simple_json.go @@ -66,9 +66,10 @@ func ValidateSimpleJsonIssuesCount(t *testing.T, params ValidationParams, result } } } + vulnerabilitiesCount := len(results.Vulnerabilities) + len(results.Secrets) + len(results.Sast) + len(results.Iacs) ValidateContent(t, params.ExactResultsMatch, - CountValidation[int]{Expected: params.Vulnerabilities, Actual: len(results.Vulnerabilities), Msg: GetValidationCountErrMsg("vulnerabilities", "simple-json", params.ExactResultsMatch, params.Vulnerabilities, len(results.Vulnerabilities))}, + CountValidation[int]{Expected: params.Vulnerabilities, Actual: vulnerabilitiesCount, Msg: GetValidationCountErrMsg("vulnerabilities", "simple-json", params.ExactResultsMatch, params.Vulnerabilities, vulnerabilitiesCount)}, CountValidation[int]{Expected: params.Sast, Actual: len(results.Sast), Msg: GetValidationCountErrMsg("sast", "simple-json", params.ExactResultsMatch, params.Sast, len(results.Sast))}, CountValidation[int]{Expected: params.Iac, Actual: len(results.Iacs), Msg: GetValidationCountErrMsg("IaC", "simple-json", params.ExactResultsMatch, params.Iac, len(results.Iacs))}, CountValidation[int]{Expected: params.Secrets, Actual: len(results.Secrets), Msg: GetValidationCountErrMsg("secrets", "simple-json", params.ExactResultsMatch, params.Secrets, len(results.Secrets))}, From 4c2df26d79f8168076f9dc4bcaa7b0cd929cf8a5 Mon Sep 17 00:00:00 2001 From: attiasas Date: Thu, 26 Sep 2024 10:26:45 +0300 Subject: [PATCH 65/82] fix tests --- .../validations/test_validate_simple_json.go | 52 ++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/utils/validations/test_validate_simple_json.go b/utils/validations/test_validate_simple_json.go index 908ebe29..1ac0f227 100644 --- a/utils/validations/test_validate_simple_json.go +++ b/utils/validations/test_validate_simple_json.go @@ -93,7 +93,7 @@ func ValidateSimpleJsonResults(t *testing.T, exactMatch bool, expected, actual f ValidateContent(t, false, NumberValidation[int]{Expected: len(expected.Errors), Actual: len(actual.Errors), Msg: "Errors count mismatch"}) // Validate vulnerabilities for _, expectedVulnerability := range expected.Vulnerabilities { - vulnerability := getVulnerabilityOrViolationByIssueId(expectedVulnerability.IssueId, actual.Vulnerabilities) + vulnerability := getVulnerabilityOrViolationByIssueId(expectedVulnerability.IssueId, expectedVulnerability.ImpactedDependencyName, expectedVulnerability.ImpactedDependencyVersion, actual.Vulnerabilities) if !assert.NotNil(t, vulnerability, fmt.Sprintf("IssueId %s not found in the vulnerabilities", expectedVulnerability.IssueId)) { return } @@ -101,7 +101,7 @@ func ValidateSimpleJsonResults(t *testing.T, exactMatch bool, expected, actual f } // Validate securityViolations for _, expectedViolation := range expected.SecurityViolations { - violation := getVulnerabilityOrViolationByIssueId(expectedViolation.IssueId, actual.SecurityViolations) + violation := getVulnerabilityOrViolationByIssueId(expectedViolation.IssueId, expectedViolation.ImpactedDependencyName, expectedViolation.ImpactedDependencyVersion, actual.SecurityViolations) if !assert.NotNil(t, violation, fmt.Sprintf("IssueId %s not found in the securityViolations", expectedViolation.IssueId)) { return } @@ -109,9 +109,9 @@ func ValidateSimpleJsonResults(t *testing.T, exactMatch bool, expected, actual f } } -func getVulnerabilityOrViolationByIssueId(issueId string, content []formats.VulnerabilityOrViolationRow) *formats.VulnerabilityOrViolationRow { +func getVulnerabilityOrViolationByIssueId(issueId, impactedDependencyName, impactedDependencyVersion string, content []formats.VulnerabilityOrViolationRow) *formats.VulnerabilityOrViolationRow { for _, result := range content { - if result.IssueId == issueId { + if result.IssueId == issueId && result.ImpactedDependencyName == impactedDependencyName && result.ImpactedDependencyVersion == impactedDependencyVersion { return &result } } @@ -126,8 +126,6 @@ func validateVulnerabilityOrViolationRow(t *testing.T, exactMatch bool, expected StringValidation{Expected: expected.Technology.String(), Actual: actual.Technology.String(), Msg: fmt.Sprintf("IssueId %s: Technology mismatch", expected.IssueId)}, ListValidation[string]{Expected: expected.References, Actual: actual.References, Msg: fmt.Sprintf("IssueId %s: References mismatch", expected.IssueId)}, - StringValidation{Expected: expected.ImpactedDependencyName, Actual: actual.ImpactedDependencyName, Msg: fmt.Sprintf("IssueId %s: ImpactedDependencyName mismatch", expected.IssueId)}, - StringValidation{Expected: expected.ImpactedDependencyVersion, Actual: actual.ImpactedDependencyVersion, Msg: fmt.Sprintf("IssueId %s: ImpactedDependencyVersion mismatch", expected.IssueId)}, StringValidation{Expected: expected.ImpactedDependencyType, Actual: actual.ImpactedDependencyType, Msg: fmt.Sprintf("IssueId %s: ImpactedDependencyType mismatch", expected.IssueId)}, ListValidation[string]{Expected: expected.FixedVersions, Actual: actual.FixedVersions, Msg: fmt.Sprintf("IssueId %s: FixedVersions mismatch", expected.IssueId)}, @@ -142,15 +140,44 @@ func validateVulnerabilityOrViolationRow(t *testing.T, exactMatch bool, expected } validateComponentRows(t, expected.IssueId, exactMatch, expected.Components, actual.Components) validateCveRows(t, expected.IssueId, exactMatch, expected.Cves, actual.Cves) - if exactMatch { - assert.ElementsMatch(t, expected.ImpactPaths, actual.ImpactPaths, fmt.Sprintf("IssueId %s: ImpactPaths mismatch", expected.IssueId)) - } else { - assert.Len(t, actual.ImpactPaths, len(expected.ImpactPaths), fmt.Sprintf("IssueId %s: ImpactPaths count mismatch", expected.IssueId)) + validateImpactPaths(t, expected.IssueId, exactMatch, expected.ImpactPaths, actual.ImpactPaths) +} + +func validateImpactPaths(t *testing.T, issueId string, exactMatch bool, expected, actual [][]formats.ComponentRow) { + assert.Len(t, actual, len(expected), fmt.Sprintf("IssueId %s: ImpactPaths count mismatch", issueId)) + if !exactMatch { + return + } + for _, expectedPath := range expected { + impactPath := getImpactPath(expectedPath, actual) + if !assert.NotNil(t, impactPath, fmt.Sprintf("IssueId %s: expected ImpactPath not found in the impactPaths", issueId)) { + return + } + } +} + +func getImpactPath(path []formats.ComponentRow, content [][]formats.ComponentRow) *[]formats.ComponentRow { + for _, result := range content { + if len(result) != len(path) { + continue + } + found := true + for i, component := range result { + if component.Name != path[i].Name || component.Version != path[i].Version { + found = false + break + } + } + if found { + return &result + } } + return nil } func validateComponentRows(t *testing.T, issueId string, exactMatch bool, expected, actual []formats.ComponentRow) { - if exactMatch && !assert.Len(t, actual, len(expected), fmt.Sprintf("IssueId %s: Components count mismatch", issueId)) { + assert.Len(t, actual, len(expected), fmt.Sprintf("IssueId %s: Components count mismatch", issueId)) + if !exactMatch { return } for _, expectedComponent := range expected { @@ -181,7 +208,8 @@ func getComponent(name, version string, content []formats.ComponentRow) *formats } func validateCveRows(t *testing.T, issueId string, exactMatch bool, expected, actual []formats.CveRow) { - if exactMatch && !assert.Len(t, actual, len(expected), fmt.Sprintf("IssueId %s: CVEs count mismatch", issueId)) { + assert.Len(t, actual, len(expected), fmt.Sprintf("IssueId %s: CVEs count mismatch", issueId)) + if !exactMatch { return } for _, expectedCve := range expected { From 99b964fa119badb7751995512c9b9d5651864fdd Mon Sep 17 00:00:00 2001 From: attiasas Date: Thu, 26 Sep 2024 14:07:38 +0300 Subject: [PATCH 66/82] attrib rename --- jas/common.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jas/common.go b/jas/common.go index fa477815..733f6c59 100644 --- a/jas/common.go +++ b/jas/common.go @@ -32,7 +32,7 @@ import ( ) const ( - NoServerUrlError = "To incorporate the ‘Advanced Security’ scans into the audit output make sure platform url is provided and valid (run 'jf c add' prior to 'jf audit' via CLI, or provide JF_URL via Frogbot)" + NoServerUrlWarn = "To incorporate the ‘Advanced Security’ scans into the audit output make sure platform url is provided and valid (run 'jf c add' prior to 'jf audit' via CLI, or provide JF_URL via Frogbot)" NoServerDetailsError = "jfrog Server details are missing" ) @@ -54,7 +54,7 @@ func CreateJasScanner(serverDetails *config.ServerDetails, validateSecrets bool, if len(serverDetails.XrayUrl) != 0 { log.Debug("Xray URL provided without platform URL") } - log.Warn(NoServerUrlError) + log.Warn(NoServerUrlWarn) return } scanner = &JasScanner{} From 8358e8d26f524f6413d36e9c782717dcf8278ca1 Mon Sep 17 00:00:00 2001 From: attiasas Date: Thu, 26 Sep 2024 14:27:15 +0300 Subject: [PATCH 67/82] fix static --- jas/common.go | 1 - 1 file changed, 1 deletion(-) diff --git a/jas/common.go b/jas/common.go index 055dc93d..b4482c7d 100644 --- a/jas/common.go +++ b/jas/common.go @@ -248,7 +248,6 @@ var FakeBasicXrayResults = []services.ScanResponse{ func InitJasTest(t *testing.T) (*JasScanner, func()) { assert.NoError(t, DownloadAnalyzerManagerIfNeeded(0)) - scanner := &JasScanner{} scanner, err := CreateJasScanner(&FakeServerDetails, false, "", GetAnalyzerManagerXscEnvVars("")) assert.NoError(t, err) return scanner, func() { From fc7def7e50b8cc3672f82824b51bdbe4d891d219 Mon Sep 17 00:00:00 2001 From: attiasas Date: Thu, 26 Sep 2024 15:14:39 +0300 Subject: [PATCH 68/82] fix tests --- jas/runner/jasrunner_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/jas/runner/jasrunner_test.go b/jas/runner/jasrunner_test.go index 6d5e4d64..cdddf403 100644 --- a/jas/runner/jasrunner_test.go +++ b/jas/runner/jasrunner_test.go @@ -38,6 +38,7 @@ func TestJasRunner_AnalyzerManagerNotExist(t *testing.T) { } func TestJasRunner(t *testing.T) { + assert.NoError(t, jas.DownloadAnalyzerManagerIfNeeded(0)) securityParallelRunnerForTest := utils.CreateSecurityParallelRunner(cliutils.Threads) targetResults := results.NewCommandResults(utils.SourceCode, "", true, true).NewScanResults(results.ScanTarget{Target: "target", Technology: techutils.Pip}) From 50cbd479c93e8549e9448940961337d3deb89dfb Mon Sep 17 00:00:00 2001 From: attiasas Date: Thu, 26 Sep 2024 15:57:42 +0300 Subject: [PATCH 69/82] push log --- utils/validations/test_validate_sarif.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index aab6425f..62d53dd6 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -158,7 +158,7 @@ func validateSarifRun(t *testing.T, exactMatch bool, expected, actual *sarif.Run // validate results for _, expectedResult := range expected.Results { result := getResultByResultId(expectedResult, actual.Results) - if !assert.NotNil(t, result, fmt.Sprintf("Run tool %s: Expected result with rule ID %s not found", expected.Tool.Driver.Name, sarifutils.GetResultRuleId(expectedResult))) { + if !assert.NotNil(t, result, fmt.Sprintf("Run tool %s: Expected result with rule ID %s not found in %v", expected.Tool.Driver.Name, sarifutils.GetResultRuleId(expectedResult), actual.Results)) { continue } validateSarifResult(t, exactMatch, expected.Tool.Driver.Name, expectedResult, result) From b33b31f3075fb697bf15c4c3cb4655ba9cc5e7cb Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 30 Sep 2024 16:48:39 +0300 Subject: [PATCH 70/82] cr review finish --- utils/results/output/securityJobSummary.go | 6 +----- utils/xsc/analyticsmetrics_test.go | 3 +++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/utils/results/output/securityJobSummary.go b/utils/results/output/securityJobSummary.go index d29b0bd8..f7fa973e 100644 --- a/utils/results/output/securityJobSummary.go +++ b/utils/results/output/securityJobSummary.go @@ -190,12 +190,8 @@ func RecordSarifOutput(cmdResults *results.SecurityCommandResults, includeVulner if err != nil || manager == nil { return } - if !cmdResults.EntitledForJas { + if !cmdResults.EntitledForJas || !commandsummary.StaticMarkdownConfig.IsExtendedSummary() { // If no JAS no GHAS - return - } - extended := true - if !extended && !commandsummary.StaticMarkdownConfig.IsExtendedSummary() { log.Info("Results can be uploaded to Github security tab automatically by upgrading your JFrog subscription.") return } diff --git a/utils/xsc/analyticsmetrics_test.go b/utils/xsc/analyticsmetrics_test.go index 1af8a864..eb723a4a 100644 --- a/utils/xsc/analyticsmetrics_test.go +++ b/utils/xsc/analyticsmetrics_test.go @@ -106,6 +106,9 @@ func TestAnalyticsMetricsService_createAuditResultsFromXscAnalyticsBasicGeneralE } } +// Create a dummy content for general event. 1 SCA scan with 1 vulnerability +// withJas - Add 2 JAS results for each scan type. +// withErr - Add an error to the results. func getDummyContentForGeneralEvent(withJas, withErr bool) *results.SecurityCommandResults { vulnerabilities := []services.Vulnerability{{IssueId: "XRAY-ID", Severity: "medium", Cves: []services.Cve{{Id: "CVE-123"}}, Components: map[string]services.Component{"issueId_2_direct_dependency": {}}}} From 8b3c1ab18b3fe2e26566278937619ee3fa300fe0 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 30 Sep 2024 17:56:48 +0300 Subject: [PATCH 71/82] fix tests --- utils/validations/test_validate_simple_json.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/validations/test_validate_simple_json.go b/utils/validations/test_validate_simple_json.go index 1ac0f227..ed0d5622 100644 --- a/utils/validations/test_validate_simple_json.go +++ b/utils/validations/test_validate_simple_json.go @@ -61,7 +61,7 @@ func ValidateSimpleJsonIssuesCount(t *testing.T, params ValidationParams, result } for _, result := range results.Secrets { if result.Applicability != nil { - if result.Applicability.Status == jasutils.Inactive.ToString() { + if result.Applicability.Status == jasutils.Inactive.String() { inactiveResults += 1 } } From 6c0b4b6d1d4795b9eb1b0cf22668dba08a57df0e Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 30 Sep 2024 19:11:29 +0300 Subject: [PATCH 72/82] fix tests --- tests/utils/test_utils.go | 14 ++++++++++++++ utils/results/output/securityJobSummary_test.go | 4 ---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index 9f4b2a47..f42c23e3 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -176,6 +176,15 @@ func convertSarifRunPathsForOS(runs ...*sarif.Run) { *location.PhysicalLocation.ArtifactLocation.URI = getJasConvertedPath(sarifutils.GetLocationFileName(location)) } } + for _, codeFlow := range result.CodeFlows { + for _, threadFlows := range codeFlow.ThreadFlows { + for _, location := range threadFlows.Locations { + if location != nil && location.Location != nil && location.Location.PhysicalLocation != nil && location.Location.PhysicalLocation.ArtifactLocation != nil && location.Location.PhysicalLocation.ArtifactLocation.URI != nil { + *location.Location.PhysicalLocation.ArtifactLocation.URI = getJasConvertedPath(sarifutils.GetLocationFileName(location.Location)) + } + } + } + } } } } @@ -217,6 +226,11 @@ func convertJasSimpleJsonPathsForOS(jas *formats.SourceCodeRow) { return } jas.Location.File = getJasConvertedPath(jas.Location.File) + if jas.Applicability != nil { + for _, evidence := range jas.Applicability.Evidence { + evidence.Location.File = getJasConvertedPath(evidence.Location.File) + } + } for _, codeFlow := range jas.CodeFlow { for _, location := range codeFlow { location.File = getJasConvertedPath(location.File) diff --git a/utils/results/output/securityJobSummary_test.go b/utils/results/output/securityJobSummary_test.go index 0324e0f2..ef744c81 100644 --- a/utils/results/output/securityJobSummary_test.go +++ b/utils/results/output/securityJobSummary_test.go @@ -45,10 +45,6 @@ func TestSaveSarifOutputOnlyForJasEntitled(t *testing.T) { name string isJasEntitled bool }{ - { - name: "JAS entitled", - isJasEntitled: true, - }, { name: "JAS not entitled", isJasEntitled: false, From a8ae84175f670dbbdea5fc84bc05ccca5a1794d1 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 1 Oct 2024 09:35:40 +0300 Subject: [PATCH 73/82] try debug --- tests/utils/test_utils.go | 9 +++++++++ utils/validations/test_validate_sarif.go | 10 +++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index f42c23e3..80f6213c 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -275,6 +275,15 @@ func convertScaSimpleJsonPathsForOS(potentialComponents *[]formats.ComponentRow, } } } + printCve(potentialCves) +} + +func printCve(potentialCves *[]formats.CveRow) { + for _, cve := range *potentialCves { + cveId := cve.Id + applicability := cve.Applicability + log.Output(fmt.Sprintf("Cve: %v, Applicability: %v", cveId, applicability)) + } } func ReadSarifResults(t *testing.T, path string) *sarif.Report { diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index 62d53dd6..7d282bf5 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -158,13 +158,21 @@ func validateSarifRun(t *testing.T, exactMatch bool, expected, actual *sarif.Run // validate results for _, expectedResult := range expected.Results { result := getResultByResultId(expectedResult, actual.Results) - if !assert.NotNil(t, result, fmt.Sprintf("Run tool %s: Expected result with rule ID %s not found in %v", expected.Tool.Driver.Name, sarifutils.GetResultRuleId(expectedResult), actual.Results)) { + if !assert.NotNil(t, result, fmt.Sprintf("Run tool %s: Expected result with rule ID %s not found in %v", expected.Tool.Driver.Name, sarifutils.GetResultRuleId(expectedResult), getResultsRuleIds(actual.Results))) { continue } validateSarifResult(t, exactMatch, expected.Tool.Driver.Name, expectedResult, result) } } +func getResultsRuleIds(results []*sarif.Result) []string { + var ruleIds []string + for _, result := range results { + ruleIds = append(ruleIds, sarifutils.GetResultRuleId(result)) + } + return ruleIds +} + func validateSarifRule(t *testing.T, exactMatch bool, toolName string, expected, actual *sarif.ReportingDescriptor) { ValidateContent(t, exactMatch, StringValidation{Expected: sarifutils.GetRuleFullDescription(expected), Actual: sarifutils.GetRuleFullDescription(actual), Msg: fmt.Sprintf("Run tool %s: Rule full description mismatch for rule %s", toolName, expected.ID)}, From 7b0c1e254df7cb54ce51fdd180d7ca3e3af86dcd Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 1 Oct 2024 13:12:59 +0300 Subject: [PATCH 74/82] fix texts + cr review --- jobTestData/debug/sarif.json | 778 -------------------------------- jobTestData/debug/simple.json | 826 ---------------------------------- tests/utils/test_utils.go | 69 ++- 3 files changed, 30 insertions(+), 1643 deletions(-) delete mode 100644 jobTestData/debug/sarif.json delete mode 100644 jobTestData/debug/simple.json diff --git a/jobTestData/debug/sarif.json b/jobTestData/debug/sarif.json deleted file mode 100644 index b8df3082..00000000 --- a/jobTestData/debug/sarif.json +++ /dev/null @@ -1,778 +0,0 @@ -{ - "version": "2.1.0", - "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", - "runs": [ - { - "tool": { - "driver": { - "informationUri": "https://jfrog.com/help/r/jfrog-security-documentation/jfrog-advanced-security", - "name": "JFrog Binary Secrets Scanner", - "rules": [ - { - "id": "REQ.SECRET.GENERIC.TEXT", - "name": "REQ.SECRET.GENERIC.TEXT", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.TEXT" - }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "help": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "not_applicable", - "conclusion": "positive" - } - }, - { - "id": "REQ.SECRET.GENERIC.CODE", - "name": "REQ.SECRET.GENERIC.CODE", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.CODE" - }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "help": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "applicable", - "conclusion": "negative", - "security-severity": "6.9" - } - }, - { - "id": "REQ.SECRET.KEYS", - "name": "REQ.SECRET.KEYS", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.SECRET.KEYS" - }, - "fullDescription": { - "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", - "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" - }, - "help": { - "text": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n", - "markdown": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" - }, - "properties": { - "applicability": "applicable", - "conclusion": "negative", - "security-severity": "6.9" - } - }, - { - "id": "REQ.CRED.PUBLIC-ONLY", - "name": "REQ.CRED.PUBLIC-ONLY", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.CRED.PUBLIC-ONLY" - }, - "fullDescription": { - "text": "", - "markdown": "" - }, - "help": { - "text": "", - "markdown": "" - }, - "properties": { - "applicability": "undetermined", - "conclusion": "private" - } - }, - { - "id": "REQ.SECRET.GENERIC.URL", - "name": "REQ.SECRET.GENERIC.URL", - "shortDescription": { - "text": "[Secret in Binary found] Scanner for REQ.SECRET.GENERIC.URL" - }, - "fullDescription": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "help": { - "text": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n", - "markdown": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - "properties": { - "applicability": "applicable", - "conclusion": "negative", - "security-severity": "6.9" - } - } - ], - "version": "1.0" - } - }, - "invocations": [ - { - "arguments": [ - "/Users/user/.jfrog/dependencies/analyzerManager/jas_scanner/jas_scanner", - "scan", - "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210780-681556384/Secrets_1726210839/config.yaml" - ], - "executionSuccessful": true, - "workingDirectory": { - "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210535-1985298017/image.tar" - } - } - ], - "results": [ - { - "properties": { - "metadata": "", - "tokenValidation": "" - }, - "ruleId": "REQ.SECRET.GENERIC.CODE", - "message": { - "text": "Hardcoded secrets were found", - "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: usr/src/app/server/index.js\nEvidence: tok************" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "usr/src/app/server/index.js" - }, - "region": { - "startLine": 5, - "startColumn": 7, - "endLine": 5, - "endColumn": 57, - "snippet": { - "text": "tok************" - } - } - }, - "logicalLocations": [ - { - "name": "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "00436fac1d19ea36302f14e892926efb" - } - }, - { - "properties": { - "metadata": "", - "tokenValidation": "" - }, - "ruleId": "REQ.SECRET.KEYS", - "message": { - "text": "Secret keys were found", - "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: usr/src/app/server/index.js\nEvidence: eyJ************" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "usr/src/app/server/index.js" - }, - "region": { - "startLine": 6, - "startColumn": 14, - "endLine": 6, - "endColumn": 24, - "snippet": { - "text": "eyJ************" - } - } - }, - "logicalLocations": [ - { - "name": "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "2550dbdb124696ae8fcc5cfd6f2b65b8" - } - }, - { - "properties": { - "metadata": "", - "tokenValidation": "" - }, - "ruleId": "REQ.SECRET.GENERIC.URL", - "message": { - "text": "Hardcoded secrets were found", - "markdown": "🔒 Found Secrets in Binary docker scanning:\nImage: platform.jfrog.io/swamp-docker/swamp:latest\nFilepath: usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc\nEvidence: htt************" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc" - }, - "region": { - "snippet": { - "text": "htt************" - } - } - } - } - ], - "fingerprints": { - "jfrogFingerprintHash": "9164423e88bbec9d1216bc5600eb7f9b" - } - } - ] - }, - { - "tool": { - "driver": { - "informationUri": "https://docs.jfrog-applications.jfrog.io/jfrog-security-features/sca", - "name": "JFrog Xray Scanner", - "rules": [ - { - "id": "CVE-2024-6119_debian:bookworm:openssl_3.0.13-1~deb12u1", - "shortDescription": { - "text": "[CVE-2024-6119] debian:bookworm:openssl 3.0.13-1~deb12u1" - }, - "help": { - "text": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | [3.0.14-1~deb12u2] |" - }, - "properties": { - "security-severity": "0.0" - } - }, - { - "id": "CVE-2024-45492_debian:bookworm:libexpat1_2.5.0-1", - "shortDescription": { - "text": "[CVE-2024-45492] debian:bookworm:libexpat1 2.5.0-1" - }, - "help": { - "text": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Not Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" - }, - "properties": { - "security-severity": "9.8" - } - }, - { - "id": "CVE-2023-51767_debian:bookworm:openssh-client:1_9.2p1-2+deb12u3", - "shortDescription": { - "text": "[CVE-2023-51767] debian:bookworm:openssh-client:1 9.2p1-2+deb12u3" - }, - "help": { - "text": "OpenSSH through 9.6, when common types of DRAM are used, might allow row hammer attacks (for authentication bypass) because the integer value of authenticated in mm_answer_authpassword does not resist flips of a single bit. NOTE: this is applicable to a certain threat model of attacker-victim co-location in which the attacker has user privileges.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 7.0 | Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" - }, - "properties": { - "security-severity": "7.0" - } - }, - { - "id": "CVE-2011-3374_debian:bookworm:apt_2.6.1", - "shortDescription": { - "text": "[CVE-2011-3374] debian:bookworm:apt 2.6.1" - }, - "help": { - "text": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.7 | Not Applicable | `sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ` | No fix available |" - }, - "properties": { - "security-severity": "3.7" - } - }, - { - "id": "CVE-2024-6119_debian:bookworm:libssl3_3.0.13-1~deb12u1", - "shortDescription": { - "text": "[CVE-2024-6119] debian:bookworm:libssl3 3.0.13-1~deb12u1" - }, - "help": { - "text": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" - }, - "properties": { - "security-severity": "0.0" - } - }, - { - "id": "XRAY-264729_cors.js_0.0.1-security", - "shortDescription": { - "text": "[XRAY-264729] cors.js 0.0.1-security" - }, - "help": { - "text": "Malicious package cors.js for Node.js", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 10.0 | Not Covered | `sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar ` | No fix available |" - }, - "properties": { - "security-severity": "10.0" - } - }, - { - "id": "CVE-2024-45490_debian:bookworm:libexpat1_2.5.0-1", - "shortDescription": { - "text": "[CVE-2024-45490] debian:bookworm:libexpat1 2.5.0-1" - }, - "help": { - "text": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.8 | Not Applicable | `sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ` | No fix available |" - }, - "properties": { - "security-severity": "9.8" - } - }, - { - "id": "CVE-2011-3374_debian:bookworm:libapt-pkg6.0_2.6.1", - "shortDescription": { - "text": "[CVE-2011-3374] debian:bookworm:libapt-pkg6.0 2.6.1" - }, - "help": { - "text": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 3.7 | Not Applicable | `sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ` | No fix available |" - }, - "properties": { - "security-severity": "3.7" - } - }, - { - "id": "CVE-2024-4741_debian:bookworm:libssl3_3.0.13-1~deb12u1", - "shortDescription": { - "text": "[CVE-2024-4741] debian:bookworm:libssl3 3.0.13-1~deb12u1" - }, - "help": { - "text": "CVE-2024-4741", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" - }, - "properties": { - "security-severity": "0.0" - } - }, - { - "id": "CVE-2024-4741_debian:bookworm:openssl_3.0.13-1~deb12u1", - "shortDescription": { - "text": "[CVE-2024-4741] debian:bookworm:openssl 3.0.13-1~deb12u1" - }, - "help": { - "text": "CVE-2024-4741", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 0.0 | Applicable | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | [3.0.14-1~deb12u1] |" - }, - "properties": { - "security-severity": "0.0" - } - }, - { - "id": "CVE-2024-38428_debian:bookworm:wget_1.21.3-1+b1", - "shortDescription": { - "text": "[CVE-2024-38428] debian:bookworm:wget 1.21.3-1+b1" - }, - "help": { - "text": "url.c in GNU Wget through 1.24.5 mishandles semicolons in the userinfo subcomponent of a URI, and thus there may be insecure behavior in which data that was supposed to be in the userinfo subcomponent is misinterpreted to be part of the host subcomponent.", - "markdown": "| Severity Score | Contextual Analysis | Direct Dependencies | Fixed Versions |\n| :---: | :---: | :---: | :---: |\n| 9.1 | Undetermined | `sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ` | No fix available |" - }, - "properties": { - "security-severity": "9.1" - } - } - ], - "version": "3.104.8" - } - }, - "invocations": [ - { - "executionSuccessful": true, - "workingDirectory": { - "uri": "/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/jfrog.cli.temp.-1726210535-1985298017/image.tar" - } - } - ], - "results": [ - { - "properties": { - "applicability": "Applicable", - "fixedVersion": "No fix available" - }, - "ruleId": "CVE-2024-6119_debian:bookworm:libssl3_3.0.13-1~deb12u1", - "ruleIndex": 4, - "level": "none", - "message": { - "text": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", - "markdown": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - "logicalLocations": [ - { - "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "5b5d2ba57a2eddf58f4579b7ebe42599" - } - }, - { - "properties": { - "applicability": "Applicable", - "fixedVersion": "[3.0.14-1~deb12u2]" - }, - "ruleId": "CVE-2024-6119_debian:bookworm:openssl_3.0.13-1~deb12u1", - "ruleIndex": 0, - "level": "none", - "message": { - "text": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", - "markdown": "[CVE-2024-6119] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - "logicalLocations": [ - { - "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "bd5908946de9c082f96e15217590eebc" - } - }, - { - "properties": { - "applicability": "Undetermined", - "fixedVersion": "No fix available" - }, - "ruleId": "CVE-2024-38428_debian:bookworm:wget_1.21.3-1+b1", - "ruleIndex": 10, - "level": "error", - "message": { - "text": "[CVE-2024-38428] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", - "markdown": "[CVE-2024-38428] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - "logicalLocations": [ - { - "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "db89861310f80a270a0a81f48d7dc974" - } - }, - { - "properties": { - "applicability": "Not Covered", - "fixedVersion": "No fix available" - }, - "ruleId": "XRAY-264729_cors.js_0.0.1-security", - "ruleIndex": 5, - "level": "error", - "message": { - "text": "[XRAY-264729] sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar ", - "markdown": "[XRAY-264729] sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" - } - }, - "logicalLocations": [ - { - "name": "ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "d653c414ef56560432b122358961104a" - } - }, - { - "properties": { - "applicability": "Not Applicable", - "fixedVersion": "No fix available" - }, - "ruleId": "CVE-2024-45490_debian:bookworm:libexpat1_2.5.0-1", - "ruleIndex": 6, - "level": "error", - "message": { - "text": "[CVE-2024-45490] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", - "markdown": "[CVE-2024-45490] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - }, - "logicalLocations": [ - { - "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "61be5170151428187e85ff7b27fd65b4" - } - }, - { - "properties": { - "applicability": "Not Applicable", - "fixedVersion": "No fix available" - }, - "ruleId": "CVE-2024-45492_debian:bookworm:libexpat1_2.5.0-1", - "ruleIndex": 1, - "level": "error", - "message": { - "text": "[CVE-2024-45492] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", - "markdown": "[CVE-2024-45492] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - }, - "logicalLocations": [ - { - "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "e47bb0a94451ed5111fabcf0ccaaeee6" - } - }, - { - "properties": { - "applicability": "Applicable", - "fixedVersion": "No fix available" - }, - "ruleId": "CVE-2023-51767_debian:bookworm:openssh-client:1_9.2p1-2+deb12u3", - "ruleIndex": 2, - "level": "note", - "message": { - "text": "[CVE-2023-51767] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar ", - "markdown": "[CVE-2023-51767] sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): 20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - }, - "logicalLocations": [ - { - "name": "20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "fe7c1c90b3e7d340890027344468b42d" - } - }, - { - "properties": { - "applicability": "Not Applicable", - "fixedVersion": "No fix available" - }, - "ruleId": "CVE-2011-3374_debian:bookworm:apt_2.6.1", - "ruleIndex": 3, - "level": "note", - "message": { - "text": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ", - "markdown": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" - } - }, - "logicalLocations": [ - { - "name": "cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "81f98a6fd77d17d7647c0ae81410b506" - } - }, - { - "properties": { - "applicability": "Not Applicable", - "fixedVersion": "No fix available" - }, - "ruleId": "CVE-2011-3374_debian:bookworm:libapt-pkg6.0_2.6.1", - "ruleIndex": 7, - "level": "note", - "message": { - "text": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar ", - "markdown": "[CVE-2011-3374] sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" - } - }, - "logicalLocations": [ - { - "name": "cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "7933bf1c7b4635012e7571e82e619db6" - } - }, - { - "properties": { - "applicability": "Applicable", - "fixedVersion": "No fix available" - }, - "ruleId": "CVE-2024-4741_debian:bookworm:libssl3_3.0.13-1~deb12u1", - "ruleIndex": 8, - "level": "none", - "message": { - "text": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", - "markdown": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - "logicalLocations": [ - { - "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "2c34553d9c75460bf14243ff13ba84c8" - } - }, - { - "properties": { - "applicability": "Applicable", - "fixedVersion": "[3.0.14-1~deb12u1]" - }, - "ruleId": "CVE-2024-4741_debian:bookworm:openssl_3.0.13-1~deb12u1", - "ruleIndex": 9, - "level": "none", - "message": { - "text": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar ", - "markdown": "[CVE-2024-4741] sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar \nImage: platform.jfrog.io/swamp-docker/swamp:latest\nLayer (sha256): f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - "logicalLocations": [ - { - "name": "f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595", - "kind": "layer", - "properties": { - "algorithm": "sha256" - } - } - ] - } - ], - "fingerprints": { - "jfrogFingerprintHash": "a374e04992f42ee827634927edd7e8d4" - } - } - ] - } - ] -} diff --git a/jobTestData/debug/simple.json b/jobTestData/debug/simple.json deleted file mode 100644 index 0fbd8a5a..00000000 --- a/jobTestData/debug/simple.json +++ /dev/null @@ -1,826 +0,0 @@ -{ - "vulnerabilities": [ - { - "severity": "Critical", - "impactedPackageName": "debian:bookworm:wget", - "impactedPackageVersion": "1.21.3-1+b1", - "impactedPackageType": "Debian", - "components": [ - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - } - ], - "summary": "url.c in GNU Wget through 1.24.5 mishandles semicolons in the userinfo subcomponent of a URI, and thus there may be insecure behavior in which data that was supposed to be in the userinfo subcomponent is misinterpreted to be part of the host subcomponent.", - "applicable": "Undetermined", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2024-38428", - "cvssV2": "", - "cvssV3": "9.1", - "applicability": { - "status": "Undetermined" - } - } - ], - "issueId": "XRAY-606103", - "references": [ - "https://git.savannah.gnu.org/cgit/wget.git/commit/?id=ed0c7c7e0e8f7298352646b2fd6e06a11e242ace", - "https://lists.gnu.org/archive/html/bug-wget/2024-06/msg00005.html", - "https://security-tracker.debian.org/tracker/CVE-2024-38428" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - { - "name": "debian:bookworm:wget", - "version": "1.21.3-1+b1", - "location": { - "file": "wget:1.21.3-1+b1" - } - } - ] - ], - "jfrogResearchInformation": null - }, - { - "severity": "Critical", - "impactedPackageName": "cors.js", - "impactedPackageVersion": "0.0.1-security", - "impactedPackageType": "npm", - "components": [ - { - "name": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar", - "version": "", - "location": { - "file": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" - } - } - ], - "summary": "Malicious package cors.js for Node.js", - "applicable": "Not Covered", - "fixedVersions": null, - "cves": null, - "issueId": "XRAY-264729", - "references": [ - "https://registry.npmjs.com" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar", - "version": "", - "location": { - "file": "sha256__ab1c0a95b2970fb44e2a4046c5c00f37a5b061e74d72b254a8975beb7d09f74f.tar" - } - }, - { - "name": "cors.js", - "version": "0.0.1-security", - "location": { - "file": "usr/src/app/node_modules/cors.js/package.json" - } - } - ] - ], - "jfrogResearchInformation": { - "severity": "Critical", - "summary": "Malicious package cors.js for Node.js", - "details": "The package cors.js for Node.js contains malicious code that installs a persistent connectback shell. The package is typosquatting the popular `cors` package. When installed, the package opens a connectback shell to the hardcoded host `107.175.32.229` on TCP port 56173. The malicious payload achieves persistency by installing a cron job that repeats every 10 seconds - `*/10 * * * * *`", - "remediation": "As with any malware, the malicious package must be completely removed, and steps must be taken care to remediate the damage that was done by the malicious package -\n\n##### Removing the malicious package\n\nRun `npm uninstall cors.js`\n\n##### Refreshing stolen credentials\n\nMany malicious packages steal stored user credentials, focusing on the following -\n\n* [Browser autocomplete](https://jfrog.com/blog/malicious-pypi-packages-stealing-credit-cards-injecting-code/) data, such as saved passwords and credit cards\n* [Environment variables](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/) passed to the malicious code\n* [Stored Discord tokens](https://jfrog.com/blog/malicious-npm-packages-are-after-your-discord-tokens-17-new-packages-disclosed/)\n* AWS / GitHub credentials stored in cleartext files\n\nIt is highly recommended to change or revoke data that is stored in the infected machine at those locations\n\n##### Stopping malicious processes\n\nMany malicious packages start malicious processes such as [connectback shells](https://jfrog.com/blog/jfrog-discloses-3-remote-access-trojans-in-pypi/) or crypto-miners. Search for any unfamiliar processes that consume a large amount of CPU or a large amount of network traffic, and stop them. On Windows, this can be facilitated with [Sysinternals Process Explorer](https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer).\n\n##### Removing installed backdoors\n\nMany malicious packages install themselves as a [persistent backdoor](https://jfrog.com/blog/npm-supply-chain-attack-targets-german-based-companies/), in order to guarantee the malicious code survives a reboot. Search for any unfamiliar binaries set to be run on startup, and remove them. On Windows, this can be facilitated with [Sysinternals Autoruns](https://docs.microsoft.com/en-us/sysinternals/downloads/autoruns).\n\n##### Defining an Xray policy that blocks downloads of Artifacts with malicious packages\n\nIt is possible to [create an Xray policy](https://www.jfrog.com/confluence/display/JFROG/Creating+Xray+Policies+and+Rules) that will not allow artifacts with identified malicious packages to be downloaded from Artifactory. To create such a policy, add a new `Security` policy and set `Minimal Severity` to `Critical`. Under `Automatic Actions` check the `Block Download` action.\n\n##### Contacting the JFrog Security Research team for additional information\n\nOptionally, if you are unsure of the full impact of the malicious package and wish to get more details, the JFrog Security Research team can help you assess the potential damage from the installed malicious package.\n\nPlease contact us at research@jfrog.com with details of the affected artifact and the name of the identified malicious package." - } - }, - { - "severity": "Low", - "impactedPackageName": "debian:bookworm:openssh-client:1", - "impactedPackageVersion": "9.2p1-2+deb12u3", - "impactedPackageType": "Debian", - "components": [ - { - "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", - "version": "", - "location": { - "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - } - ], - "summary": "OpenSSH through 9.6, when common types of DRAM are used, might allow row hammer attacks (for authentication bypass) because the integer value of authenticated in mm_answer_authpassword does not resist flips of a single bit. NOTE: this is applicable to a certain threat model of attacker-victim co-location in which the attacker has user privileges.", - "applicable": "Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2023-51767", - "cvssV2": "", - "cvssV3": "7.0", - "applicability": { - "status": "Applicable", - "scannerDescription": "The CVE is always applicable.\n\nNote - The vulnerability is hardware-dependent." - } - } - ], - "issueId": "XRAY-585612", - "references": [ - "https://arxiv.org/abs/2309.02545", - "https://github.com/openssh/openssh-portable/blob/8241b9c0529228b4b86d88b1a6076fb9f97e4a99/monitor.c#L878", - "https://github.com/openssh/openssh-portable/blob/8241b9c0529228b4b86d88b1a6076fb9f97e4a99/auth-passwd.c#L77", - "https://bugzilla.redhat.com/show_bug.cgi?id=2255850", - "https://security-tracker.debian.org/tracker/CVE-2023-51767", - "https://ubuntu.com/security/CVE-2023-51767", - "https://security.netapp.com/advisory/ntap-20240125-0006/", - "https://access.redhat.com/security/cve/CVE-2023-51767" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", - "version": "", - "location": { - "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - }, - { - "name": "debian:bookworm:openssh-client:1", - "version": "9.2p1-2+deb12u3", - "location": { - "file": "openssh-client:1:9.2p1-2+deb12u3" - } - } - ] - ], - "jfrogResearchInformation": { - "severity": "Low", - "summary": "The RowHammer fault injection attack can theoretically lead to local authentication bypass in OpenSSH.", - "details": "[OpenSSH](https://www.openssh.com/) is a popular open-source implementation of the SSH (Secure Shell) protocol, providing encrypted communication over a network.\nIt was discovered that the OpenSSH authentication logic can be susceptible in some cases to a side-channel fault injection attack. The attack can theoretically be carried out by a local attacker which eventually bypass OpenSSH authentication mechanism.\n\nThis vulnerability currently lacks widely known published exploits, and its exploitation is considered highly complex. The intricacies of the attack, combined with the absence of well-documented exploits, contribute to the difficulty in achieving successful exploitation. Furthermore, it's essential to note that the susceptibility to this vulnerability is hardware-dependent, and the success of an attack relies on probabilities associated with the specific hardware configuration. \n\nThe vulnerability is theoretically exploitable by several different ways, the only two published ways are:\n\nIn the OpenSSH function `mm_answer_authpassword()`, a stack variable `authenticated`, is assigned to the value of the function `auth_password()` which returns 1/0 and then returned. If the value of `authenticated` is 1, the SSH connection will be established. Since `authenticated` is stored on the stack, therefore in DRAM, a local attacker could flip this 32-bit integer least significant bit, thus, bypass authentication.\n\nAnother possible exploit is the `result` stack variable in `auth_password()` function. It is initialized to 0 and set to 1 if the password is correct. \nSimilarly to the previous method, this attack requires a single bit flip of the `result` variable in order for the function to return 1 and bypass the authentication.\n\nAttackers can trigger the vulnerability via a RowHammer fault injection. The Rowhammer bug is a hardware reliability issue in which an attacker repeatedly accesses (hammers) DRAM cells to cause unauthorized changes in physically adjacent memory locations.\nSimply put:\n\n* A specific register value(`authenticated`/`result` value) is pushed onto the stack during program execution. \n* The stack, where the register value is stored, is identified to be located in a memory row susceptible to bit flips (flippable row) due to the RowHammer vulnerability in DRAM.\n* The attacker performs a series of rapid and repeated memory accesses to the adjacent rows of the flippable row in the DRAM. This repeated access exploits the RowHammer vulnerability, inducing bit flips in the targeted flippable row.\n* Due to the RowHammer effect, bit flips occur in the flippable row, potentially corrupting the data stored there.\n* After inducing bit flips in the flippable row, the attacker manipulates the program's control flow to pop the corrupted value from the stack into a register.\n* The register now holds a value that has been corrupted through the RowHammer attack. Now the `authenticated`/`result` variables hold this corrupted value thus it can lead to authentication bypass, as it may impact the control flow in a way advantageous to the attacker.", - "severityReasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The vulnerability depends on the OS and hardware. It was only evaluated in one test environment, therefore results for other conditions might differ. The attacker must be extremely familiar with the details of the exploited system (ex. know the exact hardware which is running the OS).", - "isPositive": true - }, - { - "name": "The issue can only be exploited by an attacker that can execute code on the vulnerable machine (excluding exceedingly rare circumstances)", - "isPositive": true - }, - { - "name": "No high-impact exploit or technical writeup were published, and exploitation of the issue with high impact is either non-trivial or completely unproven", - "description": "Exploitation is extremely non-trivial (even theoretically), no public exploits have been published.", - "isPositive": true - }, - { - "name": "The reported CVSS was either wrongly calculated, downgraded by other vendors, or does not reflect the vulnerability's impact", - "description": "The vulnerability's attack complexity is significantly higher than what the CVSS represents.", - "isPositive": true - } - ] - } - }, - { - "severity": "Unknown", - "impactedPackageName": "debian:bookworm:libssl3", - "impactedPackageVersion": "3.0.13-1~deb12u1", - "impactedPackageType": "Debian", - "components": [ - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - } - ], - "summary": "CVE-2024-4741", - "applicable": "Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2024-4741", - "cvssV2": "", - "cvssV3": "", - "applicability": { - "status": "Applicable", - "scannerDescription": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called.", - "evidence": [ - { - "file": "usr/local/bin/node", - "reason": "References to the vulnerable functions were found" - } - ] - } - } - ], - "issueId": "XRAY-603657", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-4741" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - { - "name": "debian:bookworm:libssl3", - "version": "3.0.13-1~deb12u1", - "location": { - "file": "libssl3:3.0.13-1~deb12u1" - } - } - ] - ], - "jfrogResearchInformation": null - }, - { - "severity": "Unknown", - "impactedPackageName": "debian:bookworm:openssl", - "impactedPackageVersion": "3.0.13-1~deb12u1", - "impactedPackageType": "Debian", - "components": [ - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - } - ], - "summary": "CVE-2024-4741", - "applicable": "Applicable", - "fixedVersions": [ - "[3.0.14-1~deb12u1]" - ], - "cves": [ - { - "id": "CVE-2024-4741", - "cvssV2": "", - "cvssV3": "", - "applicability": { - "status": "Applicable", - "scannerDescription": "The scanner checks whether the vulnerable function `SSL_free_buffers` is called.", - "evidence": [ - { - "file": "usr/local/bin/node", - "reason": "References to the vulnerable functions were found" - } - ] - } - } - ], - "issueId": "XRAY-603657", - "references": [ - "https://security-tracker.debian.org/tracker/CVE-2024-4741" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - { - "name": "debian:bookworm:openssl", - "version": "3.0.13-1~deb12u1", - "location": { - "file": "openssl:3.0.13-1~deb12u1" - } - } - ] - ], - "jfrogResearchInformation": null - }, - { - "severity": "Unknown", - "impactedPackageName": "debian:bookworm:libssl3", - "impactedPackageVersion": "3.0.13-1~deb12u1", - "impactedPackageType": "Debian", - "components": [ - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - } - ], - "summary": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", - "applicable": "Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2024-6119", - "cvssV2": "", - "cvssV3": "", - "applicability": { - "status": "Applicable", - "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`", - "evidence": [ - { - "file": "usr/local/bin/node", - "reason": "References to the vulnerable functions were found" - } - ] - } - } - ], - "issueId": "XRAY-632747", - "references": [ - "https://openssl-library.org/news/secadv/20240903.txt", - "https://github.com/openssl/openssl/commit/621f3729831b05ee828a3203eddb621d014ff2b2", - "https://github.com/openssl/openssl/commit/05f360d9e849a1b277db628f1f13083a7f8dd04f", - "https://security-tracker.debian.org/tracker/CVE-2024-6119", - "https://github.com/openssl/openssl/commit/7dfcee2cd2a63b2c64b9b4b0850be64cb695b0a0", - "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - { - "name": "debian:bookworm:libssl3", - "version": "3.0.13-1~deb12u1", - "location": { - "file": "libssl3:3.0.13-1~deb12u1" - } - } - ] - ], - "jfrogResearchInformation": { - "severity": "Medium", - "summary": "Out of bounds read in OpenSSL clients can lead to denial of service when using non-default TLS verification options and connecting to malicious TLS servers", - "severityReasons": [ - { - "name": "The issue has an exploit published", - "description": "The fix commit contains PoC certificates that trigger the denial of service issue" - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "The attacker must make the victim client connect to their malicious TLS server, in order to serve the malformed TLS certificate. The victim client must use OpenSSL and must enable non-default certificate verification options, either -\n\n* DNS verification - by using `X509_VERIFY_PARAM_set1_host` or `X509_check_host`\n* Email verification - by using ` X509_VERIFY_PARAM_set1_email` or `X509_check_email`", - "isPositive": true - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "Denial of service of a TLS clients only. This out of bounds read cannot lead to data disclosure.", - "isPositive": true - } - ] - } - }, - { - "severity": "Unknown", - "impactedPackageName": "debian:bookworm:openssl", - "impactedPackageVersion": "3.0.13-1~deb12u1", - "impactedPackageType": "Debian", - "components": [ - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - } - ], - "summary": "Issue summary: Applications performing certificate name checks (e.g., TLS\nclients checking server certificates) may attempt to read an invalid memory\naddress resulting in abnormal termination of the application process.\n\nImpact summary: Abnormal termination of an application can a cause a denial of\nservice.\n\nApplications performing certificate name checks (e.g., TLS clients checking\nserver certificates) may attempt to read an invalid memory address when\ncomparing the expected name with an `otherName` subject alternative name of an\nX.509 certificate. This may result in an exception that terminates the\napplication program.\n\nNote that basic certificate chain validation (signatures, dates, ...) is not\naffected, the denial of service can occur only when the application also\nspecifies an expected DNS name, Email address or IP address.\n\nTLS servers rarely solicit client certificates, and even when they do, they\ngenerally don't perform a name check against a reference identifier (expected\nidentity), but rather extract the presented identity after checking the\ncertificate chain. So TLS servers are generally not affected and the severity\nof the issue is Moderate.\n\nThe FIPS modules in 3.3, 3.2, 3.1 and 3.0 are not affected by this issue.", - "applicable": "Applicable", - "fixedVersions": [ - "[3.0.14-1~deb12u2]" - ], - "cves": [ - { - "id": "CVE-2024-6119", - "cvssV2": "", - "cvssV3": "", - "applicability": { - "status": "Applicable", - "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `X509_VERIFY_PARAM_set1_email`\n\n- `X509_check_email`\n\n- `X509_VERIFY_PARAM_set1_host`\n\n- `X509_check_host`", - "evidence": [ - { - "file": "usr/local/bin/node", - "reason": "References to the vulnerable functions were found" - } - ] - } - } - ], - "issueId": "XRAY-632747", - "references": [ - "https://openssl-library.org/news/secadv/20240903.txt", - "https://github.com/openssl/openssl/commit/621f3729831b05ee828a3203eddb621d014ff2b2", - "https://github.com/openssl/openssl/commit/05f360d9e849a1b277db628f1f13083a7f8dd04f", - "https://security-tracker.debian.org/tracker/CVE-2024-6119", - "https://github.com/openssl/openssl/commit/7dfcee2cd2a63b2c64b9b4b0850be64cb695b0a0", - "https://github.com/openssl/openssl/commit/06d1dc3fa96a2ba5a3e22735a033012aadc9f0d6" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar", - "version": "", - "location": { - "file": "sha256__f21c087a3964a446bce1aa4e3ec7cf82020dd77ad14f1cf4ea49cbb32eda1595.tar" - } - }, - { - "name": "debian:bookworm:openssl", - "version": "3.0.13-1~deb12u1", - "location": { - "file": "openssl:3.0.13-1~deb12u1" - } - } - ] - ], - "jfrogResearchInformation": { - "severity": "Medium", - "summary": "Out of bounds read in OpenSSL clients can lead to denial of service when using non-default TLS verification options and connecting to malicious TLS servers", - "severityReasons": [ - { - "name": "The issue has an exploit published", - "description": "The fix commit contains PoC certificates that trigger the denial of service issue" - }, - { - "name": "The prerequisites for exploiting the issue are extremely unlikely", - "description": "The attacker must make the victim client connect to their malicious TLS server, in order to serve the malformed TLS certificate. The victim client must use OpenSSL and must enable non-default certificate verification options, either -\n\n* DNS verification - by using `X509_VERIFY_PARAM_set1_host` or `X509_check_host`\n* Email verification - by using ` X509_VERIFY_PARAM_set1_email` or `X509_check_email`", - "isPositive": true - }, - { - "name": "The issue cannot result in a severe impact (such as remote code execution)", - "description": "Denial of service of a TLS clients only. This out of bounds read cannot lead to data disclosure.", - "isPositive": true - } - ] - } - }, - { - "severity": "Critical", - "impactedPackageName": "debian:bookworm:libexpat1", - "impactedPackageVersion": "2.5.0-1", - "impactedPackageType": "Debian", - "components": [ - { - "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", - "version": "", - "location": { - "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - } - ], - "summary": "An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.", - "applicable": "Not Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2024-45490", - "cvssV2": "", - "cvssV3": "9.8", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether any of the following vulnerable functions are called:\n\n- `XML_Parse()`\n- `XML_ParseBuffer()`\n\nAn additional condition, which the scanner currently does not check, is that the `len` parameter which is passed to those functions is user-controlled." - } - } - ], - "issueId": "XRAY-632613", - "references": [ - "https://github.com/libexpat/libexpat/issues/887", - "https://security-tracker.debian.org/tracker/CVE-2024-45490", - "https://github.com/libexpat/libexpat/pull/890" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", - "version": "", - "location": { - "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - }, - { - "name": "debian:bookworm:libexpat1", - "version": "2.5.0-1", - "location": { - "file": "libexpat1:2.5.0-1" - } - } - ] - ], - "jfrogResearchInformation": null - }, - { - "severity": "Critical", - "impactedPackageName": "debian:bookworm:libexpat1", - "impactedPackageVersion": "2.5.0-1", - "impactedPackageType": "Debian", - "components": [ - { - "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", - "version": "", - "location": { - "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - } - ], - "summary": "An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).", - "applicable": "Not Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2024-45492", - "cvssV2": "", - "cvssV3": "9.8", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks whether the current binary was compiled with 32-bit architecture and if any of the vulnerable functions are called:\n\n- `XML_ParseBuffer()`\n- `XML_Parse()`\n\nNote - the vulnerability occurs when certain inputs are passed to those functions." - } - } - ], - "issueId": "XRAY-632612", - "references": [ - "https://github.com/libexpat/libexpat/issues/889", - "https://security-tracker.debian.org/tracker/CVE-2024-45492", - "https://github.com/libexpat/libexpat/pull/892" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar", - "version": "", - "location": { - "file": "sha256__20f026ae0a91ba4668a54b46f39853dd4c114a84cfedb4144ff24521d3e6dcb1.tar" - } - }, - { - "name": "debian:bookworm:libexpat1", - "version": "2.5.0-1", - "location": { - "file": "libexpat1:2.5.0-1" - } - } - ] - ], - "jfrogResearchInformation": null - }, - { - "severity": "Low", - "impactedPackageName": "debian:bookworm:apt", - "impactedPackageVersion": "2.6.1", - "impactedPackageType": "Debian", - "components": [ - { - "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", - "version": "", - "location": { - "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" - } - } - ], - "summary": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", - "applicable": "Not Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2011-3374", - "cvssV2": "4.3", - "cvssV3": "3.7", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." - } - } - ], - "issueId": "XRAY-34417", - "references": [ - "https://people.canonical.com/~ubuntu-security/cve/2011/CVE-2011-3374.html", - "https://seclists.org/fulldisclosure/2011/Sep/221", - "https://ubuntu.com/security/CVE-2011-3374", - "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=642480", - "https://access.redhat.com/security/cve/cve-2011-3374", - "https://snyk.io/vuln/SNYK-LINUX-APT-116518", - "https://security-tracker.debian.org/tracker/CVE-2011-3374" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", - "version": "", - "location": { - "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" - } - }, - { - "name": "debian:bookworm:apt", - "version": "2.6.1", - "location": { - "file": "apt:2.6.1" - } - } - ] - ], - "jfrogResearchInformation": { - "severity": "High", - "summary": "Improper signature validation in apt-key may enable Man-in-the-Middle attacks and result in code execution.", - "details": "`apt-key` is [`apt`](https://github.com/Debian/apt)'s key management utility, and is used to manage the keys that are used by `apt` to authenticate packages.\n\nA vulnerability in `apt-key`'s `net-update` function exists, in which [`GPG`](https://www.gnupg.org/) keys, that are used for signing packages and validating their authenticity, aren't validated correctly. The `net-update` function pulls the signing keys that should be added from an insecure location (`http://...`), exposing it to a Man-in-the-Middle attack in which malicious signing keys could be added to the system's keyring. This issue happens due to a vulnerability in the `add_keys_with_veirfy_against_master_keyring()` function, which allows adding signing keys without proper signature validation. \n\nThis vulnerability then potentially allows a malicious actor to perform a Man-in-the-Middle attack on a target, by making it validate malicious packages that were signed with the `GPG` signing key used by the attacker. Effectively, this means that `apt` can be duped to install malicious services and daemons with root privileges.\n\nThe conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man In The Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from [python-apt](https://pypi.org/project/python-apt/) Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.\n\nDo note that `apt-key` is **deprecated** and shouldn't be used, and in most Debian versions `ARCHIVE_KEYRING_URI` is not defined, making this vulnerability unexploitable in most Debian systems.", - "severityReasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the python-apt Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", - "isPositive": true - }, - { - "name": "The issue can be exploited by attackers over the network", - "description": "This vulnerability is remotely exploitable when the applicability conditions apply." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Remote code execution is possible when the applicability conditions apply." - }, - { - "name": "The issue has an exploit published", - "description": "The reporter of this issue has provided a GPG key that can be used for an actual attack, as well as a simple PoC example." - } - ], - "remediation": "##### Deployment mitigations\n\n* Dot not execute `apt-key` command, as it is deprecated.\n* Remove the URI configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`." - } - }, - { - "severity": "Low", - "impactedPackageName": "debian:bookworm:libapt-pkg6.0", - "impactedPackageVersion": "2.6.1", - "impactedPackageType": "Debian", - "components": [ - { - "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", - "version": "", - "location": { - "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" - } - } - ], - "summary": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.", - "applicable": "Not Applicable", - "fixedVersions": null, - "cves": [ - { - "id": "CVE-2011-3374", - "cvssV2": "4.3", - "cvssV3": "3.7", - "applicability": { - "status": "Not Applicable", - "scannerDescription": "The scanner checks if the vulnerable variable `ARCHIVE_KEYRING_URI` in `/usr/bin/apt-key` is not empty and not commented out. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n\nThe below prerequisites are also crucial for exploitability but are not checked in the scanner:\n\n1. The command apt-key net-update should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the `python-apt` Python module should be called. This is for the malicious keys download.\n\n2. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine." - } - } - ], - "issueId": "XRAY-34417", - "references": [ - "https://people.canonical.com/~ubuntu-security/cve/2011/CVE-2011-3374.html", - "https://seclists.org/fulldisclosure/2011/Sep/221", - "https://ubuntu.com/security/CVE-2011-3374", - "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=642480", - "https://access.redhat.com/security/cve/cve-2011-3374", - "https://snyk.io/vuln/SNYK-LINUX-APT-116518", - "https://security-tracker.debian.org/tracker/CVE-2011-3374" - ], - "impactPaths": [ - [ - { - "name": "platform.jfrog.io/swamp-docker/swamp", - "version": "latest" - }, - { - "name": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar", - "version": "", - "location": { - "file": "sha256__cedb364ef937c7e51179d8e514bdd98644bac5fdc82a45d784ef91afe4bc647e.tar" - } - }, - { - "name": "debian:bookworm:libapt-pkg6.0", - "version": "2.6.1", - "location": { - "file": "libapt-pkg6.0:2.6.1" - } - } - ] - ], - "jfrogResearchInformation": { - "severity": "High", - "summary": "Improper signature validation in apt-key may enable Man-in-the-Middle attacks and result in code execution.", - "details": "`apt-key` is [`apt`](https://github.com/Debian/apt)'s key management utility, and is used to manage the keys that are used by `apt` to authenticate packages.\n\nA vulnerability in `apt-key`'s `net-update` function exists, in which [`GPG`](https://www.gnupg.org/) keys, that are used for signing packages and validating their authenticity, aren't validated correctly. The `net-update` function pulls the signing keys that should be added from an insecure location (`http://...`), exposing it to a Man-in-the-Middle attack in which malicious signing keys could be added to the system's keyring. This issue happens due to a vulnerability in the `add_keys_with_veirfy_against_master_keyring()` function, which allows adding signing keys without proper signature validation. \n\nThis vulnerability then potentially allows a malicious actor to perform a Man-in-the-Middle attack on a target, by making it validate malicious packages that were signed with the `GPG` signing key used by the attacker. Effectively, this means that `apt` can be duped to install malicious services and daemons with root privileges.\n\nThe conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man In The Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from [python-apt](https://pypi.org/project/python-apt/) Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.\n\nDo note that `apt-key` is **deprecated** and shouldn't be used, and in most Debian versions `ARCHIVE_KEYRING_URI` is not defined, making this vulnerability unexploitable in most Debian systems.", - "severityReasons": [ - { - "name": "Exploitation of the issue is only possible when the vulnerable component is used in a specific manner. The attacker has to perform per-target research to determine the vulnerable attack vector", - "description": "The conditions for this vulnerability to be applicable:\n \n1. A valid URI should be configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`. This is the URI that an attacker would need to target in a Man-in-the-Middle attack.\n2. The command `apt-key net-update` should be executed on the affected system, or alternatively `apt.auth.net_update()` function from the python-apt Python module should be called. This is for the malicious keys download.\n3. After the execution of `apt-key net-update`, APT packages should be installed or updated on the machine.", - "isPositive": true - }, - { - "name": "The issue can be exploited by attackers over the network", - "description": "This vulnerability is remotely exploitable when the applicability conditions apply." - }, - { - "name": "The issue results in a severe impact (such as remote code execution)", - "description": "Remote code execution is possible when the applicability conditions apply." - }, - { - "name": "The issue has an exploit published", - "description": "The reporter of this issue has provided a GPG key that can be used for an actual attack, as well as a simple PoC example." - } - ], - "remediation": "##### Deployment mitigations\n\n* Dot not execute `apt-key` command, as it is deprecated.\n* Remove the URI configured in `ARCHIVE_KEYRING_URI` variable in the file `/usr/bin/apt-key`." - } - } - ], - "securityViolations": null, - "licensesViolations": null, - "licenses": null, - "operationalRiskViolations": null, - "secrets": [ - { - "severity": "Medium", - "file": "usr/src/app/server/scripts/__pycache__/fetch_github_repo.cpython-311.pyc", - "snippet": "htt************", - "finding": "Hardcoded secrets were found", - "scannerDescription": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - { - "severity": "Medium", - "file": "private/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/tmpsfyn_3d1/unpacked/filesystem/blobs/sha256/9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0/usr/src/app/server/index.js", - "startLine": 5, - "startColumn": 7, - "endLine": 5, - "endColumn": 57, - "snippet": "tok************", - "finding": "Hardcoded secrets were found", - "scannerDescription": "Storing hardcoded secrets in your source code or binary artifact could lead to several risks.\n\nIf the secret is associated with a wide scope of privileges, attackers could extract it from the source code or binary artifact and use it maliciously to attack many targets. For example, if the hardcoded password gives high-privilege access to an AWS account, the attackers may be able to query/modify company-wide sensitive data without per-user authentication.\n\n## Best practices\n\nUse safe storage when storing high-privilege secrets such as passwords and tokens, for example -\n\n* ### Environment Variables\n\nEnvironment variables are set outside of the application code, and can be dynamically passed to the application only when needed, for example -\n`SECRET_VAR=MySecret ./my_application`\nThis way, `MySecret` does not have to be hardcoded into `my_application`.\n\nNote that if your entire binary artifact is published (ex. a Docker container published to Docker Hub), the value for the environment variable must not be stored in the artifact itself (ex. inside the `Dockerfile` or one of the container's files) but rather must be passed dynamically, for example in the `docker run` call as an argument.\n\n* ### Secret management services\n\nExternal vendors offer cloud-based secret management services, that provide proper access control to each secret. The given access to each secret can be dynamically modified or even revoked. Some examples include -\n\n* [Hashicorp Vault](https://www.vaultproject.io)\n* [AWS KMS](https://aws.amazon.com/kms) (Key Management Service)\n* [Google Cloud KMS](https://cloud.google.com/security-key-management)\n\n## Least-privilege principle\n\nStoring a secret in a hardcoded manner can be made safer, by making sure the secret grants the least amount of privilege as needed by the application.\nFor example - if the application needs to read a specific table from a specific database, and the secret grants access to perform this operation **only** (meaning - no access to other tables, no write access at all) then the damage from any secret leaks is mitigated.\nThat being said, it is still not recommended to store secrets in a hardcoded manner, since this type of storage does not offer any way to revoke or moderate the usage of the secret.\n" - }, - { - "severity": "Medium", - "file": "private/var/folders/xv/th4cksxn7jv9wjrdnn1h4tj00000gq/T/tmpsfyn_3d1/unpacked/filesystem/blobs/sha256/9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0/usr/src/app/server/index.js", - "startLine": 6, - "startColumn": 14, - "endLine": 6, - "endColumn": 24, - "snippet": "eyJ************", - "finding": "Secret keys were found", - "scannerDescription": "\nStoring an API key in the image could lead to several risks.\n\nIf the key is associated with a wide scope of privileges, attackers could extract it from a single image or firmware and use it maliciously to attack many targets. For example, if the embedded key allows querying/modifying data for all cloud user accounts, without per-user authentication, the attackers who extract it would gain access to system-wide data.\n\nIf the cloud/SaaS provider bills by key usage - for example, every million queries cost the key's owner a fixed sum of money - attackers could use the keys for their own purposes (or just as a form of vandalism), incurring a large cost to the legitimate user or operator.\n\n## Best practices\n\nUse narrow scopes for stored API keys. As much as possible, API keys should be unique per host and require additional authentication with the user's individual credentials for any sensitive actions.\n\nAvoid placing keys whose use incurs costs directly in the image. Store the key with any software or hardware protection available on the host for key storage (such as operating system key-stores, hardware cryptographic storage mechanisms or cloud-managed secure storage services such as [AWS KMS](https://aws.amazon.com/kms/)).\n\nTokens that were detected as exposed should be revoked and replaced -\n\n* [AWS Key Revocation](https://aws.amazon.com/premiumsupport/knowledge-center/delete-access-key/#:~:text=If%20you%20see%20a%20warning,the%20confirmation%20box%2C%20choose%20Deactivate.)\n* [GCP Key Revocation](https://www.trendmicro.com/cloudoneconformity/knowledge-base/gcp/CloudIAM/delete-api-keys.html)\n* [Azure Key Revocation](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#revoke-a-pat)\n* [GitHub Key Revocation](https://docs.github.com/en/rest/apps/oauth-applications#delete-an-app-authorization)\n" - } - ], - "iacViolations": null, - "sastViolations": null, - "errors": null -} diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index 80f6213c..888c29b2 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -164,23 +164,23 @@ func ReadCmdScanResults(t *testing.T, path string) *results.SecurityCommandResul } func convertSarifRunPathsForOS(runs ...*sarif.Run) { - for _, run := range runs { - for _, invocation := range run.Invocations { - if invocation.WorkingDirectory != nil && invocation.WorkingDirectory.URI != nil { - *invocation.WorkingDirectory.URI = filepath.FromSlash(sarifutils.GetInvocationWorkingDirectory(invocation)) + for r := range runs { + for i := range runs[r].Invocations { + if runs[r].Invocations[i].WorkingDirectory != nil && runs[r].Invocations[i].WorkingDirectory.URI != nil { + *runs[r].Invocations[i].WorkingDirectory.URI = filepath.FromSlash(sarifutils.GetInvocationWorkingDirectory(runs[r].Invocations[i])) } } - for _, result := range run.Results { - for _, location := range result.Locations { - if location != nil && location.PhysicalLocation != nil && location.PhysicalLocation.ArtifactLocation != nil && location.PhysicalLocation.ArtifactLocation.URI != nil { - *location.PhysicalLocation.ArtifactLocation.URI = getJasConvertedPath(sarifutils.GetLocationFileName(location)) + for i := range runs[r].Results { + for j := range runs[r].Results[i].Locations { + if runs[r].Results[i].Locations[j] != nil && runs[r].Results[i].Locations[j].PhysicalLocation != nil && runs[r].Results[i].Locations[j].PhysicalLocation.ArtifactLocation != nil && runs[r].Results[i].Locations[j].PhysicalLocation.ArtifactLocation.URI != nil { + *runs[r].Results[i].Locations[j].PhysicalLocation.ArtifactLocation.URI = getJasConvertedPath(sarifutils.GetLocationFileName(runs[r].Results[i].Locations[j])) } } - for _, codeFlow := range result.CodeFlows { - for _, threadFlows := range codeFlow.ThreadFlows { - for _, location := range threadFlows.Locations { - if location != nil && location.Location != nil && location.Location.PhysicalLocation != nil && location.Location.PhysicalLocation.ArtifactLocation != nil && location.Location.PhysicalLocation.ArtifactLocation.URI != nil { - *location.Location.PhysicalLocation.ArtifactLocation.URI = getJasConvertedPath(sarifutils.GetLocationFileName(location.Location)) + for j := range runs[r].Results[i].CodeFlows { + for k := range runs[r].Results[i].CodeFlows[j].ThreadFlows { + for l := range runs[r].Results[i].CodeFlows[j].ThreadFlows[k].Locations { + if runs[r].Results[i].CodeFlows[j].ThreadFlows[k].Locations[l] != nil && runs[r].Results[i].CodeFlows[j].ThreadFlows[k].Locations[l].Location != nil && runs[r].Results[i].CodeFlows[j].ThreadFlows[k].Locations[l].Location.PhysicalLocation != nil && runs[r].Results[i].CodeFlows[j].ThreadFlows[k].Locations[l].Location.PhysicalLocation.ArtifactLocation != nil && runs[r].Results[i].CodeFlows[j].ThreadFlows[k].Locations[l].Location.PhysicalLocation.ArtifactLocation.URI != nil { + *runs[r].Results[i].CodeFlows[j].ThreadFlows[k].Locations[l].Location.PhysicalLocation.ArtifactLocation.URI = getJasConvertedPath(sarifutils.GetLocationFileName(runs[r].Results[i].CodeFlows[j].ThreadFlows[k].Locations[l].Location)) } } } @@ -227,13 +227,13 @@ func convertJasSimpleJsonPathsForOS(jas *formats.SourceCodeRow) { } jas.Location.File = getJasConvertedPath(jas.Location.File) if jas.Applicability != nil { - for _, evidence := range jas.Applicability.Evidence { - evidence.Location.File = getJasConvertedPath(evidence.Location.File) + for i := range jas.Applicability.Evidence { + jas.Applicability.Evidence[i].Location.File = getJasConvertedPath(jas.Applicability.Evidence[i].Location.File) } } - for _, codeFlow := range jas.CodeFlow { - for _, location := range codeFlow { - location.File = getJasConvertedPath(location.File) + for i := range jas.CodeFlow { + for j := range jas.CodeFlow[i] { + jas.CodeFlow[i][j].File = getJasConvertedPath(jas.CodeFlow[i][j].File) } } } @@ -241,27 +241,27 @@ func convertJasSimpleJsonPathsForOS(jas *formats.SourceCodeRow) { func convertScaSimpleJsonPathsForOS(potentialComponents *[]formats.ComponentRow, potentialImpactPaths *[][]formats.ComponentRow, potentialImpactedDependencyDetails *formats.ImpactedDependencyDetails, potentialCves *[]formats.CveRow) { if potentialComponents != nil { components := *potentialComponents - for _, component := range components { - if component.Location != nil { - component.Location.File = filepath.FromSlash(component.Location.File) + for i := range components { + if components[i].Location != nil { + components[i].Location.File = filepath.FromSlash(components[i].Location.File) } } } if potentialImpactPaths != nil { impactPaths := *potentialImpactPaths - for _, impactPath := range impactPaths { - for _, pathComponent := range impactPath { - if pathComponent.Location != nil { - pathComponent.Location.File = filepath.FromSlash(pathComponent.Location.File) + for i := range impactPaths { + for j := range impactPaths[i] { + if impactPaths[i][j].Location != nil { + impactPaths[i][j].Location.File = filepath.FromSlash(impactPaths[i][j].Location.File) } } } } if potentialImpactedDependencyDetails != nil { impactedDependencyDetails := *potentialImpactedDependencyDetails - for _, component := range impactedDependencyDetails.Components { - if component.Location != nil { - component.Location.File = filepath.FromSlash(component.Location.File) + for i := range impactedDependencyDetails.Components { + if impactedDependencyDetails.Components[i].Location != nil { + impactedDependencyDetails.Components[i].Location.File = filepath.FromSlash(impactedDependencyDetails.Components[i].Location.File) } } } @@ -269,21 +269,12 @@ func convertScaSimpleJsonPathsForOS(potentialComponents *[]formats.ComponentRow, cves := *potentialCves for _, cve := range cves { if cve.Applicability != nil { - for _, evidence := range cve.Applicability.Evidence { - evidence.Location.File = filepath.FromSlash(evidence.Location.File) + for i := range cve.Applicability.Evidence { + cve.Applicability.Evidence[i].Location.File = filepath.FromSlash(cve.Applicability.Evidence[i].Location.File) } } } } - printCve(potentialCves) -} - -func printCve(potentialCves *[]formats.CveRow) { - for _, cve := range *potentialCves { - cveId := cve.Id - applicability := cve.Applicability - log.Output(fmt.Sprintf("Cve: %v, Applicability: %v", cveId, applicability)) - } } func ReadSarifResults(t *testing.T, path string) *sarif.Report { From d240a3175b560e46699e07134421f8aab4337dc7 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 1 Oct 2024 14:09:08 +0300 Subject: [PATCH 75/82] fix merge --- audit_test.go | 38 +++++++++++--------------------------- commands/audit/audit.go | 4 ++++ 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/audit_test.go b/audit_test.go index 8e0f485e..2859832f 100644 --- a/audit_test.go +++ b/audit_test.go @@ -553,35 +553,35 @@ func addDummyPackageDescriptor(t *testing.T, hasPackageJson bool) { func TestXrayAuditSastCppFlagSimpleJson(t *testing.T) { output := testAuditC(t, string(format.SimpleJson), true) - securityTestUtils.VerifySimpleJsonJasResults(t, output, 1, 0, 0, 0, 0, 0, 0, 0, 0) - + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ + Vulnerabilities: 1, + Sast: 1, + }) } func TestXrayAuditWithoutSastCppFlagSimpleJson(t *testing.T) { output := testAuditC(t, string(format.SimpleJson), false) - securityTestUtils.VerifySimpleJsonJasResults(t, output, 0, 0, 0, 0, 0, 0, 0, 0, 0) + // verify no results for Sast + validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{}) } // Helper for both C & Cpp Sast scans tests func testAuditC(t *testing.T, format string, enableCppFlag bool) string { - cliToRun, cleanUp := securityTestUtils.InitTestWithMockCommandOrParams(t, getJasAuditMockCommand) - defer cleanUp() securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion) + tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t) defer createTempDirCallback() - cProjectPath := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects", "package-managers", "c") + projectDir := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), filepath.Join("projects", "package-managers", "c")) // Copy the c project from the testdata to a temp dir - assert.NoError(t, biutils.CopyDir(cProjectPath, tempDirPath, true, nil)) + assert.NoError(t, biutils.CopyDir(projectDir, tempDirPath, true, nil)) prevWd := securityTestUtils.ChangeWD(t, tempDirPath) defer clientTests.ChangeDirAndAssert(t, prevWd) - watchName, deleteWatch := securityTestUtils.CreateTestWatch(t, "audit-policy", "audit-watch", xrayUtils.High) - defer deleteWatch() if enableCppFlag { unsetEnv := clientTests.SetEnvWithCallbackAndAssert(t, "JFROG_SAST_ENABLE_CPP", "1") defer unsetEnv() } - args := []string{"audit", "--licenses", "--vuln", "--format=" + format, "--watches=" + watchName, "--fail=false"} - return cliToRun.WithoutCredentials().RunCliCmdWithOutput(t, args...) + args := []string{"audit", "--format=" + format} + return securityTests.PlatformCli.WithoutCredentials().RunCliCmdWithOutput(t, args...) } func TestXrayAuditNotEntitledForJas(t *testing.T) { @@ -591,22 +591,6 @@ func TestXrayAuditNotEntitledForJas(t *testing.T) { validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{Vulnerabilities: 8}) } -func getJasAuditMockCommand() components.Command { - return components.Command{ - Name: docs.Audit, - Flags: docs.GetCommandFlags(docs.Audit), - Action: func(c *components.Context) error { - auditCmd, err := cli.CreateAuditCmd(c) - if err != nil { - return err - } - // Disable Jas for this test - auditCmd.SetUseJas(true) - return progressbar.ExecWithProgress(auditCmd) - }, - } -} - func getNoJasAuditMockCommand() components.Command { return components.Command{ Name: docs.Audit, diff --git a/commands/audit/audit.go b/commands/audit/audit.go index fcfd94ac..b54d5430 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -315,6 +315,10 @@ func downloadAnalyzerManagerAndRunScanners(auditParallelRunner *utils.SecurityPa func initCmdResults(entitledForJas, secretValidation bool, params *AuditParams) (cmdResults *results.SecurityCommandResults) { cmdResults = results.NewCommandResults(utils.SourceCode, params.xrayVersion, entitledForJas, secretValidation).SetMultiScanId(params.commonGraphScanParams.MultiScanId) detectScanTargets(cmdResults, params) + if params.IsRecursiveScan() && len(params.workingDirs) == 1 && len(cmdResults.Targets) == 0 { + // No SCA targets were detected, add the root directory as a target for JAS scans. + cmdResults.NewScanResults(results.ScanTarget{Target: params.workingDirs[0]}) + } scanInfo, err := coreutils.GetJsonIndent(cmdResults) if err != nil { return From 511a21ddb80f101ac815a3b2c5e741a395351108 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 1 Oct 2024 16:26:58 +0300 Subject: [PATCH 76/82] try debug --- tests/utils/test_utils.go | 8 ++++---- utils/validations/test_validate_sarif.go | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index 888c29b2..9d7a5fa5 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -267,10 +267,10 @@ func convertScaSimpleJsonPathsForOS(potentialComponents *[]formats.ComponentRow, } if potentialCves != nil { cves := *potentialCves - for _, cve := range cves { - if cve.Applicability != nil { - for i := range cve.Applicability.Evidence { - cve.Applicability.Evidence[i].Location.File = filepath.FromSlash(cve.Applicability.Evidence[i].Location.File) + for i := range cves { + if cves[i].Applicability != nil { + for i := range cves[i].Applicability.Evidence { + cves[i].Applicability.Evidence[i].Location.File = filepath.FromSlash(cves[i].Applicability.Evidence[i].Location.File) } } } diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index 7d282bf5..ea728f48 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -9,6 +9,7 @@ import ( "github.com/jfrog/jfrog-cli-security/utils/jasutils" "github.com/jfrog/jfrog-cli-security/utils/results" "github.com/jfrog/jfrog-cli-security/utils/results/conversion/sarifparser" + "github.com/jfrog/jfrog-client-go/utils/log" "github.com/owenrumney/go-sarif/v2/sarif" "github.com/stretchr/testify/assert" ) @@ -186,11 +187,16 @@ func validateSarifRule(t *testing.T, exactMatch bool, toolName string, expected, } func getResultByResultId(expected *sarif.Result, actual []*sarif.Result) *sarif.Result { + log.Output("====================================") + log.Output(fmt.Sprintf(":: Actual results with expected results: %s", getResultId(expected))) for _, result := range actual { + + log.Output(fmt.Sprintf("Compare actual result (isPotential=%t, hasSameLocations=%t) with expected result: %s", isPotentialSimilarResults(expected, result), hasSameLocations(expected, result) , getResultId(result))) if isPotentialSimilarResults(expected, result) && hasSameLocations(expected, result) { return result } } + log.Output("====================================") return nil } @@ -198,6 +204,18 @@ func isPotentialSimilarResults(expected, actual *sarif.Result) bool { return sarifutils.GetResultRuleId(actual) == sarifutils.GetResultRuleId(expected) && sarifutils.GetResultMsgText(actual) == sarifutils.GetResultMsgText(expected) && sarifutils.GetResultProperty(sarifparser.WatchSarifPropertyKey, actual) == sarifutils.GetResultProperty(sarifparser.WatchSarifPropertyKey, expected) } +func getResultId(result *sarif.Result) string { + return fmt.Sprintf("%s-%s-%s-%s", sarifutils.GetResultRuleId(result), sarifutils.GetResultMsgText(result), sarifutils.GetResultProperty(sarifparser.WatchSarifPropertyKey, result), getLocationsId(result.Locations)) +} + +func getLocationsId(locations []*sarif.Location) string { + var locationsId string + for _, location := range locations { + locationsId += sarifutils.GetLocationId(location) + } + return locationsId +} + func hasSameLocations(expected, actual *sarif.Result) bool { if len(expected.Locations) != len(actual.Locations) { return false From b5e69312e825c0d9b81d73d07034bcbcaea6725e Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 1 Oct 2024 17:39:10 +0300 Subject: [PATCH 77/82] fix tests --- audit_test.go | 5 ++-- utils/results/conversion/convertor.go | 4 ++- .../conversion/sarifparser/sarifparser.go | 26 +++++++++++-------- .../sarifparser/sarifparser_test.go | 2 +- utils/results/output/securityJobSummary.go | 1 + 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/audit_test.go b/audit_test.go index 2859832f..bc35b4a2 100644 --- a/audit_test.go +++ b/audit_test.go @@ -568,10 +568,9 @@ func TestXrayAuditWithoutSastCppFlagSimpleJson(t *testing.T) { // Helper for both C & Cpp Sast scans tests func testAuditC(t *testing.T, format string, enableCppFlag bool) string { securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion) - tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t) defer createTempDirCallback() - projectDir := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), filepath.Join("projects", "package-managers", "c")) + projectDir := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects", "package-managers", "c") // Copy the c project from the testdata to a temp dir assert.NoError(t, biutils.CopyDir(projectDir, tempDirPath, true, nil)) prevWd := securityTestUtils.ChangeWD(t, tempDirPath) @@ -581,7 +580,7 @@ func testAuditC(t *testing.T, format string, enableCppFlag bool) string { defer unsetEnv() } args := []string{"audit", "--format=" + format} - return securityTests.PlatformCli.WithoutCredentials().RunCliCmdWithOutput(t, args...) + return securityTests.PlatformCli.RunCliCmdWithOutput(t, args...) } func TestXrayAuditNotEntitledForJas(t *testing.T) { diff --git a/utils/results/conversion/convertor.go b/utils/results/conversion/convertor.go index 979e2705..e95ceed7 100644 --- a/utils/results/conversion/convertor.go +++ b/utils/results/conversion/convertor.go @@ -23,6 +23,8 @@ type ResultConvertParams struct { HasViolationContext bool // Control if the output should include vulnerabilities information IncludeVulnerabilities bool + // If true and commandType.IsTargetBinary(), binary inner paths in results will be converted to the CI job file (relevant only for SARIF) + PatchBinaryPaths bool // Control if the output should include licenses information IncludeLicenses bool // Control and override converting command results as multi target results, if nil will be determined by the results.HasMultipleTargets() @@ -65,7 +67,7 @@ func (c *CommandResultsConvertor) ConvertToSimpleJson(cmdResults *results.Securi } func (c *CommandResultsConvertor) ConvertToSarif(cmdResults *results.SecurityCommandResults) (sarifReport *sarif.Report, err error) { - parser := sarifparser.NewCmdResultsSarifConverter(c.Params.IncludeVulnerabilities, c.Params.HasViolationContext) + parser := sarifparser.NewCmdResultsSarifConverter(c.Params.IncludeVulnerabilities, c.Params.HasViolationContext, c.Params.PatchBinaryPaths) return parseCommandResults(c.Params, parser, cmdResults) } diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index 33e70919..3a762576 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -48,6 +48,8 @@ type CmdResultsSarifConverter struct { // Include vulnerabilities/violations in the output includeVulnerabilities bool hasViolationContext bool + // If we are running on Github actions, we need to add/change information to the output + patchBinaryPaths bool // Current stream parse cache information current *sarif.Report scaCurrentRun *sarif.Run @@ -59,8 +61,8 @@ type CmdResultsSarifConverter struct { currentCmdType utils.CommandType } -func NewCmdResultsSarifConverter(includeVulnerabilities, hasViolationContext bool) *CmdResultsSarifConverter { - return &CmdResultsSarifConverter{includeVulnerabilities: includeVulnerabilities, hasViolationContext: hasViolationContext} +func NewCmdResultsSarifConverter(includeVulnerabilities, hasViolationContext, patchBinaryPaths bool) *CmdResultsSarifConverter { + return &CmdResultsSarifConverter{includeVulnerabilities: includeVulnerabilities, hasViolationContext: hasViolationContext, patchBinaryPaths: patchBinaryPaths} } func (sc *CmdResultsSarifConverter) Get() (*sarif.Report, error) { @@ -94,7 +96,7 @@ func (sc *CmdResultsSarifConverter) ParseNewTargetResults(target results.ScanTar } if sc.scaCurrentRun != nil { // Flush the current run - sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.ScaScan, sc.currentTarget, sc.scaCurrentRun)...) + sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.ScaScan, sc.patchBinaryPaths, sc.currentTarget, sc.scaCurrentRun)...) } sc.currentTarget = target if sc.hasViolationContext || sc.includeVulnerabilities { @@ -163,7 +165,7 @@ func (sc *CmdResultsSarifConverter) ParseSecrets(target results.ScanTarget, secr if sc.current == nil { return results.ErrResetConvertor } - sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.SecretsScan, target, secrets...)...) + sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.SecretsScan, sc.patchBinaryPaths, target, secrets...)...) return } @@ -174,7 +176,7 @@ func (sc *CmdResultsSarifConverter) ParseIacs(target results.ScanTarget, iacs .. if sc.current == nil { return results.ErrResetConvertor } - sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.IacScan, target, iacs...)...) + sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.IacScan, sc.patchBinaryPaths, target, iacs...)...) return } @@ -185,7 +187,7 @@ func (sc *CmdResultsSarifConverter) ParseSast(target results.ScanTarget, sast .. if sc.current == nil { return results.ErrResetConvertor } - sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.SastScan, target, sast...)...) + sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.SastScan, sc.patchBinaryPaths, target, sast...)...) return } @@ -414,7 +416,7 @@ func getScaLicenseViolationMarkdown(depName, version, key string, directDependen return fmt.Sprintf("%s
Direct dependencies:
%s", getLicenseViolationSummary(depName, version, key), formattedDirectDependencies), nil } -func patchRunsToPassIngestionRules(cmdType utils.CommandType, subScanType utils.SubScanType, target results.ScanTarget, runs ...*sarif.Run) []*sarif.Run { +func patchRunsToPassIngestionRules(cmdType utils.CommandType, subScanType utils.SubScanType, patchBinaryPaths bool, target results.ScanTarget, runs ...*sarif.Run) []*sarif.Run { // Since we run in temp directories files should be relative // Patch by converting the file paths to relative paths according to the invocations convertPaths(cmdType, subScanType, runs...) @@ -429,7 +431,7 @@ func patchRunsToPassIngestionRules(cmdType utils.CommandType, subScanType utils. if patched.Tool.Driver != nil { patched.Tool.Driver.Rules = patchRules(cmdType, subScanType, run.Tool.Driver.Rules...) } - patched.Results = patchResults(cmdType, subScanType, target, run, run.Results...) + patched.Results = patchResults(cmdType, subScanType, patchBinaryPaths, target, run, run.Results...) patchedRuns = append(patchedRuns, patched) } return patchedRuns @@ -494,7 +496,7 @@ func patchRules(commandType utils.CommandType, subScanType utils.SubScanType, ru return } -func patchResults(commandType utils.CommandType, subScanType utils.SubScanType, target results.ScanTarget, run *sarif.Run, results ...*sarif.Result) (patched []*sarif.Result) { +func patchResults(commandType utils.CommandType, subScanType utils.SubScanType, patchBinaryPaths bool, target results.ScanTarget, run *sarif.Run, results ...*sarif.Result) (patched []*sarif.Result) { patched = []*sarif.Result{} for _, result := range results { if len(result.Locations) == 0 { @@ -511,8 +513,10 @@ func patchResults(commandType utils.CommandType, subScanType utils.SubScanType, markdown = getScaInBinaryMarkdownMsg(commandType, target, result) } sarifutils.SetResultMsgMarkdown(markdown, result) - // For Binary scans, override the physical location if applicable (after data already used for markdown) - result = convertBinaryPhysicalLocations(commandType, run, result) + if patchBinaryPaths { + // For Binary scans, override the physical location if applicable (after data already used for markdown) + result = convertBinaryPhysicalLocations(commandType, run, result) + } // Calculate the fingerprints if not exists if !sarifutils.IsFingerprintsExists(result) { if err := calculateResultFingerprints(commandType, run, result); err != nil { diff --git a/utils/results/conversion/sarifparser/sarifparser_test.go b/utils/results/conversion/sarifparser/sarifparser_test.go index 6cc29dd2..dc0060f6 100644 --- a/utils/results/conversion/sarifparser/sarifparser_test.go +++ b/utils/results/conversion/sarifparser/sarifparser_test.go @@ -489,7 +489,7 @@ func TestPatchRunsToPassIngestionRules(t *testing.T) { revertWd := clientTests.ChangeDirWithCallback(t, wd, dockerfileDir) defer revertWd() } - patchedRuns := patchRunsToPassIngestionRules(tc.cmdType, tc.subScan, tc.target, tc.input...) + patchedRuns := patchRunsToPassIngestionRules(tc.cmdType, tc.subScan, true, tc.target, tc.input...) assert.ElementsMatch(t, tc.expectedResults, patchedRuns) }) } diff --git a/utils/results/output/securityJobSummary.go b/utils/results/output/securityJobSummary.go index f7fa973e..cf5c913e 100644 --- a/utils/results/output/securityJobSummary.go +++ b/utils/results/output/securityJobSummary.go @@ -199,6 +199,7 @@ func RecordSarifOutput(cmdResults *results.SecurityCommandResults, includeVulner sarifReport, err := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{ IncludeVulnerabilities: includeVulnerabilities, HasViolationContext: hasViolationContext, + PatchBinaryPaths: true, RequestedScans: requestedScans, Pretty: true, }).ConvertToSarif(cmdResults) From 3c71a653204958f6bb9d95f80ab37338d1875ea7 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 7 Oct 2024 09:35:27 +0300 Subject: [PATCH 78/82] add sca run id to sarif result --- utils/formats/sarifutils/sarifutils.go | 14 ++++++++++++++ .../conversion/sarifparser/sarifparser.go | 11 +++++++++++ utils/validations/test_validate_sarif.go | 18 +++++++++++------- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/utils/formats/sarifutils/sarifutils.go b/utils/formats/sarifutils/sarifutils.go index 05604f84..fcc2ebe4 100644 --- a/utils/formats/sarifutils/sarifutils.go +++ b/utils/formats/sarifutils/sarifutils.go @@ -37,6 +37,20 @@ func GetToolVersion(run *sarif.Run) string { return "" } +func GetRunGUID(run *sarif.Run) string { + if run != nil && run.AutomationDetails != nil && run.AutomationDetails.GUID != nil { + return *run.AutomationDetails.GUID + } + return "" +} + +func SetRunGUID(guid string, run *sarif.Run) { + if run.AutomationDetails == nil { + run.AutomationDetails = sarif.NewRunAutomationDetails() + } + run.AutomationDetails.GUID = &guid +} + func CopyRunMetadata(run *sarif.Run) (copied *sarif.Run) { if run == nil { return diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index 3a762576..ca7405fa 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -53,6 +53,7 @@ type CmdResultsSarifConverter struct { // Current stream parse cache information current *sarif.Report scaCurrentRun *sarif.Run + scaCurrentRunIds *datastructures.Set[string] currentTarget results.ScanTarget parsedScaKeys *datastructures.Set[string] // General information on the current command results @@ -95,10 +96,18 @@ func (sc *CmdResultsSarifConverter) ParseNewTargetResults(target results.ScanTar return results.ErrResetConvertor } if sc.scaCurrentRun != nil { + if sc.scaCurrentRunIds.Size() > 0 { + id := sc.scaCurrentRunIds.ToSlice()[0] + if sc.scaCurrentRunIds.Size() > 1 { + log.Warn(fmt.Sprintf("Multiple SCA scan ids parsed as a single run. Setting run as %s, from %v", id, sc.scaCurrentRunIds.ToSlice())) + } + sarifutils.SetRunGUID(id, sc.scaCurrentRun) + } // Flush the current run sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.ScaScan, sc.patchBinaryPaths, sc.currentTarget, sc.scaCurrentRun)...) } sc.currentTarget = target + sc.scaCurrentRunIds = datastructures.MakeSet[string]() if sc.hasViolationContext || sc.includeVulnerabilities { // Create Sca Run if requested to parse all vulnerabilities/violations to it sc.scaCurrentRun = sc.createScaRun(sc.currentTarget, len(errors)) @@ -138,6 +147,7 @@ func (sc *CmdResultsSarifConverter) ParseViolations(target results.ScanTarget, s return } sc.addScaResultsToCurrentRun(sarifRules, sarifResults...) + sc.scaCurrentRunIds.Add(scanResponse.ScanId) return } @@ -150,6 +160,7 @@ func (sc *CmdResultsSarifConverter) ParseVulnerabilities(target results.ScanTarg return } sc.addScaResultsToCurrentRun(sarifRules, sarifResults...) + sc.scaCurrentRunIds.Add(scanResponse.ScanId) return } diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index ea728f48..2b8c97ed 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -147,6 +147,10 @@ func validateSarifRun(t *testing.T, exactMatch bool, expected, actual *sarif.Run PointerValidation[string]{Expected: expected.Tool.Driver.InformationURI, Actual: actual.Tool.Driver.InformationURI, Msg: fmt.Sprintf("Run tool information URI mismatch for tool %s", expected.Tool.Driver.Name)}, PointerValidation[string]{Expected: expected.Tool.Driver.Version, Actual: actual.Tool.Driver.Version, Msg: fmt.Sprintf("Run tool version mismatch for tool %s", expected.Tool.Driver.Name)}, ) + validateSarifProperties(t, exactMatch, expected.Properties, actual.Properties, expected.Tool.Driver.Name, "run") + if ValidateContent(t, exactMatch, PointerValidation[sarif.RunAutomationDetails]{Expected: expected.AutomationDetails, Actual: actual.AutomationDetails, Msg: fmt.Sprintf("Run tool automation details mismatch for tool %s", expected.Tool.Driver.Name)}) && expected.AutomationDetails != nil { + ValidateContent(t, exactMatch, StringValidation{Expected: sarifutils.GetRunGUID(expected), Actual: sarifutils.GetRunGUID(actual), Msg: fmt.Sprintf("Run tool GUID mismatch for tool %s", expected.Tool.Driver.Name)}) + } // validate rules for _, expectedRule := range expected.Tool.Driver.Rules { rule, err := actual.GetRuleById(expectedRule.ID) @@ -183,7 +187,7 @@ func validateSarifRule(t *testing.T, exactMatch bool, toolName string, expected, StringValidation{Expected: sarifutils.GetRuleHelpMarkdown(expected), Actual: sarifutils.GetRuleHelpMarkdown(actual), Msg: fmt.Sprintf("Run tool %s: Rule help markdown mismatch for rule %s", toolName, expected.ID)}, ) // validate properties - validateSarifProperties(t, exactMatch, expected.Properties, actual.Properties, toolName, expected.ID) + validateSarifProperties(t, exactMatch, expected.Properties, actual.Properties, toolName, fmt.Sprintf("rule %s", expected.ID)) } func getResultByResultId(expected *sarif.Result, actual []*sarif.Result) *sarif.Result { @@ -234,7 +238,7 @@ func validateSarifResult(t *testing.T, exactMatch bool, toolName string, expecte StringValidation{Expected: sarifutils.GetResultLevel(expected), Actual: sarifutils.GetResultLevel(actual), Msg: fmt.Sprintf("Run tool %s: Result level mismatch for rule %s", toolName, sarifutils.GetResultRuleId(expected))}, ) // validate properties - validateSarifProperties(t, exactMatch, expected.Properties, actual.Properties, toolName, sarifutils.GetResultRuleId(expected)) + validateSarifProperties(t, exactMatch, expected.Properties, actual.Properties, toolName, fmt.Sprintf("result rule %s", sarifutils.GetResultRuleId(expected))) // validate locations for _, expectedLocation := range expected.Locations { location := getLocationById(expectedLocation, actual.Locations) @@ -253,20 +257,20 @@ func getLocationById(expected *sarif.Location, actual []*sarif.Location) *sarif. return nil } -func validateSarifProperties(t *testing.T, exactMatch bool, expected, actual map[string]interface{}, toolName, ruleID string) { +func validateSarifProperties(t *testing.T, exactMatch bool, expected, actual map[string]interface{}, toolName, id string) { for key, expectedValue := range expected { actualValue, ok := actual[key] - if !assert.True(t, ok, fmt.Sprintf("Run tool %s: Expected property with key %s not found for rule %s", toolName, key, ruleID)) { + if !assert.True(t, ok, fmt.Sprintf("Run tool %s: Expected property with key %s not found for %s", toolName, key, id)) { continue } // If the property is a string, compare the string values if expectedStr, ok := expectedValue.(string); ok { actualStr, ok := actualValue.(string) - if assert.True(t, ok, fmt.Sprintf("Run tool %s: Expected property with key %s is not a string for rule %s", toolName, key, ruleID)) { - ValidateContent(t, exactMatch, StringValidation{Expected: expectedStr, Actual: actualStr, Msg: fmt.Sprintf("Run tool %s: Rule property mismatch for rule %s", toolName, ruleID)}) + if assert.True(t, ok, fmt.Sprintf("Run tool %s: Expected property with key %s is not a string for %s", toolName, key, id)) { + ValidateContent(t, exactMatch, StringValidation{Expected: expectedStr, Actual: actualStr, Msg: fmt.Sprintf("Run tool %s: Rule property mismatch for rule %s", toolName, id)}) continue } - assert.Fail(t, fmt.Sprintf("Run tool %s: Expected property with key %s is a string for rule %s", toolName, key, ruleID)) + assert.Fail(t, fmt.Sprintf("Run tool %s: Expected property with key %s is a string for %s", toolName, key, id)) } } } From d4dbf93ec3a2f8c24488b5ff49cbc33fee0b3d19 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 7 Oct 2024 09:40:54 +0300 Subject: [PATCH 79/82] remove scan id --- utils/formats/sarifutils/sarifutils.go | 14 -------------- .../results/conversion/sarifparser/sarifparser.go | 13 +------------ utils/results/output/securityJobSummary.go | 2 +- utils/validations/test_validate_sarif.go | 5 +---- 4 files changed, 3 insertions(+), 31 deletions(-) diff --git a/utils/formats/sarifutils/sarifutils.go b/utils/formats/sarifutils/sarifutils.go index fcc2ebe4..05604f84 100644 --- a/utils/formats/sarifutils/sarifutils.go +++ b/utils/formats/sarifutils/sarifutils.go @@ -37,20 +37,6 @@ func GetToolVersion(run *sarif.Run) string { return "" } -func GetRunGUID(run *sarif.Run) string { - if run != nil && run.AutomationDetails != nil && run.AutomationDetails.GUID != nil { - return *run.AutomationDetails.GUID - } - return "" -} - -func SetRunGUID(guid string, run *sarif.Run) { - if run.AutomationDetails == nil { - run.AutomationDetails = sarif.NewRunAutomationDetails() - } - run.AutomationDetails.GUID = &guid -} - func CopyRunMetadata(run *sarif.Run) (copied *sarif.Run) { if run == nil { return diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go index ca7405fa..dd51fbb6 100644 --- a/utils/results/conversion/sarifparser/sarifparser.go +++ b/utils/results/conversion/sarifparser/sarifparser.go @@ -49,11 +49,10 @@ type CmdResultsSarifConverter struct { includeVulnerabilities bool hasViolationContext bool // If we are running on Github actions, we need to add/change information to the output - patchBinaryPaths bool + patchBinaryPaths bool // Current stream parse cache information current *sarif.Report scaCurrentRun *sarif.Run - scaCurrentRunIds *datastructures.Set[string] currentTarget results.ScanTarget parsedScaKeys *datastructures.Set[string] // General information on the current command results @@ -96,18 +95,10 @@ func (sc *CmdResultsSarifConverter) ParseNewTargetResults(target results.ScanTar return results.ErrResetConvertor } if sc.scaCurrentRun != nil { - if sc.scaCurrentRunIds.Size() > 0 { - id := sc.scaCurrentRunIds.ToSlice()[0] - if sc.scaCurrentRunIds.Size() > 1 { - log.Warn(fmt.Sprintf("Multiple SCA scan ids parsed as a single run. Setting run as %s, from %v", id, sc.scaCurrentRunIds.ToSlice())) - } - sarifutils.SetRunGUID(id, sc.scaCurrentRun) - } // Flush the current run sc.current.Runs = append(sc.current.Runs, patchRunsToPassIngestionRules(sc.currentCmdType, utils.ScaScan, sc.patchBinaryPaths, sc.currentTarget, sc.scaCurrentRun)...) } sc.currentTarget = target - sc.scaCurrentRunIds = datastructures.MakeSet[string]() if sc.hasViolationContext || sc.includeVulnerabilities { // Create Sca Run if requested to parse all vulnerabilities/violations to it sc.scaCurrentRun = sc.createScaRun(sc.currentTarget, len(errors)) @@ -147,7 +138,6 @@ func (sc *CmdResultsSarifConverter) ParseViolations(target results.ScanTarget, s return } sc.addScaResultsToCurrentRun(sarifRules, sarifResults...) - sc.scaCurrentRunIds.Add(scanResponse.ScanId) return } @@ -160,7 +150,6 @@ func (sc *CmdResultsSarifConverter) ParseVulnerabilities(target results.ScanTarg return } sc.addScaResultsToCurrentRun(sarifRules, sarifResults...) - sc.scaCurrentRunIds.Add(scanResponse.ScanId) return } diff --git a/utils/results/output/securityJobSummary.go b/utils/results/output/securityJobSummary.go index cf5c913e..ae15da2c 100644 --- a/utils/results/output/securityJobSummary.go +++ b/utils/results/output/securityJobSummary.go @@ -199,7 +199,7 @@ func RecordSarifOutput(cmdResults *results.SecurityCommandResults, includeVulner sarifReport, err := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{ IncludeVulnerabilities: includeVulnerabilities, HasViolationContext: hasViolationContext, - PatchBinaryPaths: true, + PatchBinaryPaths: true, RequestedScans: requestedScans, Pretty: true, }).ConvertToSarif(cmdResults) diff --git a/utils/validations/test_validate_sarif.go b/utils/validations/test_validate_sarif.go index 2b8c97ed..8c90481d 100644 --- a/utils/validations/test_validate_sarif.go +++ b/utils/validations/test_validate_sarif.go @@ -148,9 +148,6 @@ func validateSarifRun(t *testing.T, exactMatch bool, expected, actual *sarif.Run PointerValidation[string]{Expected: expected.Tool.Driver.Version, Actual: actual.Tool.Driver.Version, Msg: fmt.Sprintf("Run tool version mismatch for tool %s", expected.Tool.Driver.Name)}, ) validateSarifProperties(t, exactMatch, expected.Properties, actual.Properties, expected.Tool.Driver.Name, "run") - if ValidateContent(t, exactMatch, PointerValidation[sarif.RunAutomationDetails]{Expected: expected.AutomationDetails, Actual: actual.AutomationDetails, Msg: fmt.Sprintf("Run tool automation details mismatch for tool %s", expected.Tool.Driver.Name)}) && expected.AutomationDetails != nil { - ValidateContent(t, exactMatch, StringValidation{Expected: sarifutils.GetRunGUID(expected), Actual: sarifutils.GetRunGUID(actual), Msg: fmt.Sprintf("Run tool GUID mismatch for tool %s", expected.Tool.Driver.Name)}) - } // validate rules for _, expectedRule := range expected.Tool.Driver.Rules { rule, err := actual.GetRuleById(expectedRule.ID) @@ -195,7 +192,7 @@ func getResultByResultId(expected *sarif.Result, actual []*sarif.Result) *sarif. log.Output(fmt.Sprintf(":: Actual results with expected results: %s", getResultId(expected))) for _, result := range actual { - log.Output(fmt.Sprintf("Compare actual result (isPotential=%t, hasSameLocations=%t) with expected result: %s", isPotentialSimilarResults(expected, result), hasSameLocations(expected, result) , getResultId(result))) + log.Output(fmt.Sprintf("Compare actual result (isPotential=%t, hasSameLocations=%t) with expected result: %s", isPotentialSimilarResults(expected, result), hasSameLocations(expected, result), getResultId(result))) if isPotentialSimilarResults(expected, result) && hasSameLocations(expected, result) { return result } From 7ecb1be3e43b169fdadbfd2fdde8bd054f7fae09 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 7 Oct 2024 09:41:33 +0300 Subject: [PATCH 80/82] update AM to 1.9.4 --- jas/analyzermanager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jas/analyzermanager.go b/jas/analyzermanager.go index 94cb8ddd..e01eb877 100644 --- a/jas/analyzermanager.go +++ b/jas/analyzermanager.go @@ -24,7 +24,7 @@ import ( const ( ApplicabilityFeatureId = "contextual_analysis" AnalyzerManagerZipName = "analyzerManager.zip" - defaultAnalyzerManagerVersion = "1.9.3" + defaultAnalyzerManagerVersion = "1.9.4" analyzerManagerDownloadPath = "xsc-gen-exe-analyzer-manager-local/v1" analyzerManagerDirName = "analyzerManager" analyzerManagerExecutableName = "analyzerManager" From 2f324ee3bd9cf50f57558180fee5640318cb363b Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 13 Oct 2024 11:10:30 +0300 Subject: [PATCH 81/82] fix conflicts --- commands/audit/audit_test.go | 8 ++++---- commands/audit/sca/yarn/yarn_test.go | 16 ++++++++++------ utils/results/results.go | 4 ++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/commands/audit/audit_test.go b/commands/audit/audit_test.go index 00ac5360..54960817 100644 --- a/commands/audit/audit_test.go +++ b/commands/audit/audit_test.go @@ -394,7 +394,7 @@ func TestAuditWithPartialResults(t *testing.T) { // TODO when applying allow-partial-results to JAS make sure to add a test case that checks failures in JAS scans + add some JAS api call to the mock server } - serverMock, serverDetails := utils.CreateXrayRestsMockServer(func(w http.ResponseWriter, r *http.Request) { + serverMock, serverDetails := validations.CreateXrayRestsMockServer(func(w http.ResponseWriter, r *http.Request) { if r.RequestURI == "/xray/api/v1/system/version" { _, err := w.Write([]byte(fmt.Sprintf(`{"xray_version": "%s", "xray_revision": "xxx"}`, scangraph.GraphScanMinXrayVersion))) if !assert.NoError(t, err) { @@ -427,16 +427,16 @@ func TestAuditWithPartialResults(t *testing.T) { SetCommonGraphScanParams(&scangraph.CommonGraphScanParams{ ScanType: scanservices.Dependency, IncludeVulnerabilities: true, - MultiScanId: utils.TestScaScanId, + MultiScanId: validations.TestScaScanId, }) auditParams.SetIsRecursiveScan(true) scanResults, err := RunAudit(auditParams) if testcase.allowPartialResults { - assert.NoError(t, scanResults.ScansErr) + assert.NoError(t, scanResults.GetErrors()) assert.NoError(t, err) } else { - assert.Error(t, scanResults.ScansErr) + assert.Error(t, scanResults.GetErrors()) assert.NoError(t, err) } }) diff --git a/commands/audit/sca/yarn/yarn_test.go b/commands/audit/sca/yarn/yarn_test.go index c060f692..46ae80c6 100644 --- a/commands/audit/sca/yarn/yarn_test.go +++ b/commands/audit/sca/yarn/yarn_test.go @@ -1,15 +1,19 @@ package yarn import ( + "os" "path/filepath" + "strings" "testing" "errors" + "github.com/jfrog/build-info-go/build" bibuildutils "github.com/jfrog/build-info-go/build/utils" biutils "github.com/jfrog/build-info-go/utils" "github.com/jfrog/jfrog-cli-core/v2/utils/tests" "github.com/jfrog/jfrog-cli-security/commands/audit/sca" + "github.com/jfrog/jfrog-cli-security/utils" "github.com/jfrog/jfrog-cli-security/utils/techutils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" @@ -18,12 +22,12 @@ import ( func TestParseYarnDependenciesList(t *testing.T) { npmId := techutils.Npm.GetPackageTypeId() - yarnDependencies := map[string]*biutils.YarnDependency{ - "pack1@npm:1.0.0": {Value: "pack1@npm:1.0.0", Details: biutils.YarnDepDetails{Version: "1.0.0", Dependencies: []biutils.YarnDependencyPointer{{Locator: "pack4@npm:4.0.0"}}}}, - "pack2@npm:2.0.0": {Value: "pack2@npm:2.0.0", Details: biutils.YarnDepDetails{Version: "2.0.0", Dependencies: []biutils.YarnDependencyPointer{{Locator: "pack4@npm:4.0.0"}, {Locator: "pack5@npm:5.0.0"}}}}, - "@jfrog/pack3@npm:3.0.0": {Value: "@jfrog/pack3@npm:3.0.0", Details: biutils.YarnDepDetails{Version: "3.0.0", Dependencies: []biutils.YarnDependencyPointer{{Locator: "pack1@virtual:c192f6b3b32cd5d11a443144e162ec3bc#npm:1.0.0"}, {Locator: "pack2@npm:2.0.0"}}}}, - "pack4@npm:4.0.0": {Value: "pack4@npm:4.0.0", Details: biutils.YarnDepDetails{Version: "4.0.0"}}, - "pack5@npm:5.0.0": {Value: "pack5@npm:5.0.0", Details: biutils.YarnDepDetails{Version: "5.0.0", Dependencies: []biutils.YarnDependencyPointer{{Locator: "pack2@npm:2.0.0"}}}}, + yarnDependencies := map[string]*bibuildutils.YarnDependency{ + "pack1@npm:1.0.0": {Value: "pack1@npm:1.0.0", Details: bibuildutils.YarnDepDetails{Version: "1.0.0", Dependencies: []bibuildutils.YarnDependencyPointer{{Locator: "pack4@npm:4.0.0"}}}}, + "pack2@npm:2.0.0": {Value: "pack2@npm:2.0.0", Details: bibuildutils.YarnDepDetails{Version: "2.0.0", Dependencies: []bibuildutils.YarnDependencyPointer{{Locator: "pack4@npm:4.0.0"}, {Locator: "pack5@npm:5.0.0"}}}}, + "@jfrog/pack3@npm:3.0.0": {Value: "@jfrog/pack3@npm:3.0.0", Details: bibuildutils.YarnDepDetails{Version: "3.0.0", Dependencies: []bibuildutils.YarnDependencyPointer{{Locator: "pack1@virtual:c192f6b3b32cd5d11a443144e162ec3bc#npm:1.0.0"}, {Locator: "pack2@npm:2.0.0"}}}}, + "pack4@npm:4.0.0": {Value: "pack4@npm:4.0.0", Details: bibuildutils.YarnDepDetails{Version: "4.0.0"}}, + "pack5@npm:5.0.0": {Value: "pack5@npm:5.0.0", Details: bibuildutils.YarnDepDetails{Version: "5.0.0", Dependencies: []bibuildutils.YarnDependencyPointer{{Locator: "pack2@npm:2.0.0"}}}}, } rootXrayId := npmId + "@jfrog/pack3:3.0.0" diff --git a/utils/results/results.go b/utils/results/results.go index a57ea7b8..cc495fa0 100644 --- a/utils/results/results.go +++ b/utils/results/results.go @@ -124,8 +124,8 @@ func (r *SecurityCommandResults) GetErrors() (err error) { return } -func (r *SecurityCommandResults) GetTechnologies() []techutils.Technology { - technologies := datastructures.MakeSet[techutils.Technology]() +func (r *SecurityCommandResults) GetTechnologies(additionalTechs ...techutils.Technology) []techutils.Technology { + technologies := datastructures.MakeSetFromElements(additionalTechs...) for _, scan := range r.Targets { technologies.AddElements(scan.GetTechnologies()...) } From 290a1fe94353405c1f6b24e9f5f60e077af2d97e Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 13 Oct 2024 17:34:59 +0300 Subject: [PATCH 82/82] fix tests --- audit_test.go | 40 +++++++++++++--------------------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/audit_test.go b/audit_test.go index bc35b4a2..76e01a53 100644 --- a/audit_test.go +++ b/audit_test.go @@ -552,7 +552,7 @@ func addDummyPackageDescriptor(t *testing.T, hasPackageJson bool) { // JAS func TestXrayAuditSastCppFlagSimpleJson(t *testing.T) { - output := testAuditC(t, string(format.SimpleJson), true) + output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("package-managers", "c"), "3", false, true) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ Vulnerabilities: 1, Sast: 1, @@ -560,33 +560,15 @@ func TestXrayAuditSastCppFlagSimpleJson(t *testing.T) { } func TestXrayAuditWithoutSastCppFlagSimpleJson(t *testing.T) { - output := testAuditC(t, string(format.SimpleJson), false) + output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("package-managers", "c"), "3", false, false) // verify no results for Sast validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{}) } -// Helper for both C & Cpp Sast scans tests -func testAuditC(t *testing.T, format string, enableCppFlag bool) string { - securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion) - tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t) - defer createTempDirCallback() - projectDir := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects", "package-managers", "c") - // Copy the c project from the testdata to a temp dir - assert.NoError(t, biutils.CopyDir(projectDir, tempDirPath, true, nil)) - prevWd := securityTestUtils.ChangeWD(t, tempDirPath) - defer clientTests.ChangeDirAndAssert(t, prevWd) - if enableCppFlag { - unsetEnv := clientTests.SetEnvWithCallbackAndAssert(t, "JFROG_SAST_ENABLE_CPP", "1") - defer unsetEnv() - } - args := []string{"audit", "--format=" + format} - return securityTests.PlatformCli.RunCliCmdWithOutput(t, args...) -} - func TestXrayAuditNotEntitledForJas(t *testing.T) { cliToRun, cleanUp := securityTestUtils.InitTestWithMockCommandOrParams(t, getNoJasAuditMockCommand) defer cleanUp() - output := testXrayAuditJas(t, cliToRun, filepath.Join("jas", "jas"), "3", false) + output := testXrayAuditJas(t, cliToRun, filepath.Join("jas", "jas"), "3", false, false) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{Vulnerabilities: 8}) } @@ -607,7 +589,7 @@ func getNoJasAuditMockCommand() components.Command { } func TestXrayAuditJasSimpleJson(t *testing.T) { - output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("jas", "jas"), "3", false) + output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("jas", "jas"), "3", false, false) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ Sast: 1, Iac: 9, @@ -623,12 +605,12 @@ func TestXrayAuditJasSimpleJson(t *testing.T) { func TestXrayAuditJasSimpleJsonWithTokenValidation(t *testing.T) { securityTestUtils.InitSecurityTest(t, jasutils.DynamicTokenValidationMinXrayVersion) - output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("jas", "jas"), "3", true) + output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("jas", "jas"), "3", true, false) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{Inactive: 5}) } func TestXrayAuditJasSimpleJsonWithOneThread(t *testing.T) { - output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("jas", "jas"), "1", false) + output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("jas", "jas"), "1", false, false) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ Sast: 1, Iac: 9, @@ -643,7 +625,7 @@ func TestXrayAuditJasSimpleJsonWithOneThread(t *testing.T) { } func TestXrayAuditJasSimpleJsonWithConfig(t *testing.T) { - output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("jas", "jas-config"), "3", false) + output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("jas", "jas-config"), "3", false, false) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ Secrets: 1, @@ -656,11 +638,11 @@ func TestXrayAuditJasSimpleJsonWithConfig(t *testing.T) { } func TestXrayAuditJasNoViolationsSimpleJson(t *testing.T) { - output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("package-managers", "npm", "npm"), "3", false) + output := testXrayAuditJas(t, securityTests.PlatformCli, filepath.Join("package-managers", "npm", "npm"), "3", false, false) validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{Vulnerabilities: 1, NotApplicable: 1}) } -func testXrayAuditJas(t *testing.T, testCli *coreTests.JfrogCli, project string, threads string, validateSecrets bool) string { +func testXrayAuditJas(t *testing.T, testCli *coreTests.JfrogCli, project string, threads string, validateSecrets, validateSastCpp bool) string { securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion) tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t) defer createTempDirCallback() @@ -678,6 +660,10 @@ func testXrayAuditJas(t *testing.T, testCli *coreTests.JfrogCli, project string, if validateSecrets { args = append(args, "--secrets", "--validate-secrets") } + if validateSastCpp { + unsetEnv := clientTests.SetEnvWithCallbackAndAssert(t, "JFROG_SAST_ENABLE_CPP", "1") + defer unsetEnv() + } return testCli.WithoutCredentials().RunCliCmdWithOutput(t, args...) }