diff --git a/lib/sarif/bandit_sarif.rb b/lib/sarif/bandit_sarif.rb index eaaf685e..ea365e76 100644 --- a/lib/sarif/bandit_sarif.rb +++ b/lib/sarif/bandit_sarif.rb @@ -38,11 +38,29 @@ def parse_error(error) end def parse_issue(issue) + # Example issue + # {"code"=>"1 import cPickle\n2 import pickle\n3 import StringIO\n", + # "col_offset"=>0, + # "end_col_offset"=>14, + # "filename"=>"./main.py", + # "issue_confidence"=>"HIGH", + # "issue_cwe"=>{"id"=>502, "link"=>"https://cwe.mitre.org/data/definitions/502.html"}, + # "issue_severity"=>"LOW", + # "issue_text"=>"Consider possible security implications associated with cPickle module.", + # "line_number"=>1, + # "line_range"=>[1], + # "more_info"=>"https://bandit.readthedocs.io/en/1.7.5/...", + # "test_id"=>"B403", + # "test_name"=>"blacklist"} + return parse_error(issue) if !issue.key?('issue_text') key = issue["filename"] + ' ' + issue["line_number"].to_s + ' ' + issue['issue_text'] return nil if @issues.include? key + cwe = issue.dig('issue_cwe', 'id') + cwe = cwe.nil? ? '' : "CWE-#{cwe}" + @issues.add(key) endline = issue['line_range'][issue['line_range'].size - 1] { @@ -51,7 +69,8 @@ def parse_issue(issue) level: issue['issue_severity'], details: (issue['issue_text']).to_s, messageStrings: { "confidence": { "text": (issue['issue_severity']).to_s }, - "severity": { "text": (issue['issue_severity']).to_s } }, + "severity": { "text": (issue['issue_severity']).to_s }, + "cwe": { "text": [cwe].to_s } }, properties: { 'severity': issue['issue_severity'].to_s }, start_line: issue["line_number"].to_i, end_line: endline, diff --git a/lib/sarif/brakeman_sarif.rb b/lib/sarif/brakeman_sarif.rb index 96ad702d..9842a7c0 100644 --- a/lib/sarif/brakeman_sarif.rb +++ b/lib/sarif/brakeman_sarif.rb @@ -38,6 +38,24 @@ def parse_error(error) end def parse_issue(issue) + # Example issue + # {"warning_type"=>"Dangerous Eval", + # "warning_code"=>13, + # "fingerprint"=>"b16e1cd0d952433f80b0403b6a74aab0e98792ea015cc1b1fa5c003cbe7d56eb", + # "check_name"=>"Evaluation", + # "message"=>"User input in eval", + # "file"=>"app/controllers/static_controller_controller.rb", + # "line"=>3, + # "link"=>"https://brakemanscanner.org/docs/warning_types/dangerous_eval/", + # "code"=>"eval(params[:evil])", + # "render_path"=>nil, + # "location"=>{"type"=>"method", "class"=>"StaticControllerController", "method"=>"index"}, + # "user_input"=>"params[:evil]", + # "confidence"=>"High", + # "cwe_id"=>[913, 95]} + + cwes = issue.fetch('cwe_id', []).map { |cwe| "CWE-#{cwe}" } + return parse_error(issue) if issue.key?('error') { @@ -47,7 +65,8 @@ def parse_issue(issue) details: (issue['message']).to_s, messageStrings: { "title": { "text": (issue['check_name']).to_s }, "type": { "text": (issue['warning_type']).to_s }, - "warning_code": { "text": (issue['warning_code']).to_s } }, + "warning_code": { "text": (issue['warning_code']).to_s }, + "cwe": { "text": cwes.to_s } }, properties: { 'fingerprint': issue['fingerprint'].to_s, 'confidence': issue['confidence'].to_s, 'severity': "", diff --git a/lib/sarif/bundle_audit_sarif.rb b/lib/sarif/bundle_audit_sarif.rb index 3ac6ded1..5e14d61d 100644 --- a/lib/sarif/bundle_audit_sarif.rb +++ b/lib/sarif/bundle_audit_sarif.rb @@ -10,6 +10,18 @@ def initialize(scan_report, repo_path = nil, scanner_config = {}) end def parse_issue(issue) + # Example issue + # {:type=>"InsecureSource", :source=>"http://rubygems.org/", :line_number=>123} + + # Another example: + # {:type=>"UnpatchedGem", :cve=>"CVE1234", :url=>"1", :line_number=>456, :name=>"boo"} + + # OSV example + # {:osvdb=>"osvd value", :url=>"3", :line_number=>789} + + # !!!! Note CVEs are not CWEs but we lack a mapping to CWE + cves = [issue.fetch(:cve, "")] + result = { id: issue[:cve] || issue[:osvdb].to_s, name: issue[:advisory_title], @@ -21,6 +33,7 @@ def parse_issue(issue) "unaffected_versions": { "text": (issue[:unaffected_versions]).to_s }, "title": { "text": (issue[:advisory_title]).to_s }, "osvdb": { "text": (issue[:osdvb]).to_s }, + "cwe": { "text": cves.to_s }, "type": { "text": (issue[:type]).to_s }, "version": { "text": (issue[:version]).to_s } }, properties: { 'severity': (issue[:cvss]).to_s }, diff --git a/lib/sarif/cargo_audit_sarif.rb b/lib/sarif/cargo_audit_sarif.rb index 7e2b0f4b..0acbac69 100644 --- a/lib/sarif/cargo_audit_sarif.rb +++ b/lib/sarif/cargo_audit_sarif.rb @@ -45,6 +45,47 @@ def parse_issue(issue) return parse_yanked(issue) if issue['kind'] == 'yanked' return nil if @issues.include?(issue.dig('advisory', 'id')) + # rubocop:disable Layout/LineLength + + # Example issue + # {"advisory"=> + # {"id"=>"RUSTSEC-2019-0010", + # "package"=>"libflate", + # "title"=>"MultiDecoder::read() drops uninitialized memory of ...", + # "description"=> + # "Affected versions of libflate have set a field of an internalnd revert ...", + # "date"=>"2019-07-04", + # "aliases"=>["CVE-2019-15552"], + # "related"=>[], + # "collection"=>"crates", + # "categories"=>[], + # "keywords"=>["drop", "use-after-free"], + # "cvss"=>"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + # "informational"=>nil, + # "references"=>[], + # "source"=>nil, + # "url"=>"https://github.com/sile/libflate/issues/35", + # "withdrawn"=>nil}, + # "versions"=>{"patched"=>[">=0.1.25"], "unaffected"=>["<0.1.14"]}, + # "affected"=>{"arch"=>[], "os"=>[], "functions"=>{"libflate::gzip::MultiDecoder::read"=>["<0.1.25, >=0.1.14"]}}, + # "package"=> + # {"name"=>"libflate", + # "version"=>"0.1.19", + # "source"=>"registry+https://github.com/rust-lang/crates.io-index", + # "checksum"=>nil, + # "dependencies"=> + # [{"name"=>"adler32", "version"=>"1.1.0", "source"=>"registry+https://github.com/rust-lang/crates.io-index"}, + # {"name"=>"crc32fast", "version"=>"1.2.0", "source"=>"registry+https://github.com/rust-lang/crates.io-index"}, + # {"name"=>"rle-decode-fast", "version"=>"1.0.1", "source"=>"registry+https://github.com/rust-lang/crates.io-index"}, + # {"name"=>"take_mut", "version"=>"0.2.2", "source"=>"registry+https://github.com/rust-lang/crates.io-index"}], + # "replace"=>nil}} + + # rubocop:enable Layout/LineLength + + # !!!! Note CVEs are not CWEs but we lack a mapping to CWE + cves = issue.dig('advisory', 'aliases') + cves = [] if cves.nil? + @issues.add(issue.dig('advisory', 'id')) advisory = issue['advisory'] || {} parsed_issue = { @@ -55,6 +96,7 @@ def parse_issue(issue) messageStrings: { "package": { "text": (advisory['package']).to_s }, "title": { "text": (advisory['title']).to_s }, "severity": { "text": (advisory['cvss']).to_s }, + "cwe": { "text": cves.to_s }, "patched_versions": { "text": issue.dig('versions', 'patched').to_s }, "unaffected_versions": { "text": issue.dig('versions', 'unaffected').to_s } }, diff --git a/lib/sarif/gosec_sarif.rb b/lib/sarif/gosec_sarif.rb index 1520f10a..a337c77d 100644 --- a/lib/sarif/gosec_sarif.rb +++ b/lib/sarif/gosec_sarif.rb @@ -62,6 +62,21 @@ def parse_issue(issue) if issue[:id] == SCANNER_ERROR issue else + # rubocop:disable Layout/LineLength + + # Example issue + # {"severity"=>"MEDIUM", + # "confidence"=>"HIGH", + # "cwe"=>{"ID"=>"78", "URL"=>"https://cwe.mitre.org/data/definitions/78.html"}, + # "rule_id"=>"G204", + # "details"=>"Subprocess launched with variable", + # "file"=>"parser.go", + # "code"=>"37: \tbuf := bytes.NewReader(b)\n38: \tcmd := exec.Command(path, \"--format\", \"json\", \"--type\", \"ast\")\n39: \tcmd.Stdin = buf\n", + # "line"=>"38", + # "column"=>"9"} + + # rubocop:enable Layout/LineLength + id = issue['details'] + ' ' + issue['file'] + ' ' + issue['line'] return nil if @issues.include?(id) @@ -77,16 +92,17 @@ def parse_issue(issue) filepath.relative_path_from(base_path).to_s end + cwe = "CWE-#{id}" @issues.add(id) { id: issue['rule_id'], - name: "CWE-#{id}", + name: cwe, level: issue['severity'], details: "#{issue['details']} \nSeverity: #{issue['severity']}\nConfidence:"\ " #{issue['confidence']}\nCWE: #{url}", messageStrings: { "severity": { "text": (issue['severity']).to_s }, "confidence": { "text": (issue['confidence']).to_s }, - "cwe": { "text": url.to_s } }, + "cwe": { "text": [cwe].to_s } }, properties: { 'severity': (issue['severity']).to_s }, start_line: issue['line'].to_i, start_column: issue['column'].to_i, diff --git a/lib/sarif/npm_audit_sarif.rb b/lib/sarif/npm_audit_sarif.rb index 729d939f..98ebd748 100644 --- a/lib/sarif/npm_audit_sarif.rb +++ b/lib/sarif/npm_audit_sarif.rb @@ -25,6 +25,36 @@ def parse_issue(issue) @results.push(id) if !@exceptions.include?(id) @issues.add(id) + # rubocop:disable Layout/LineLength + + # Example issue + # {:findings=>[{:version=>"1.2.0", :paths=>["merge"]}], + # :metadata=>nil, + # :vulnerable_versions=>"<2.1.1", + # :module_name=>"merge", + # :severity=>"high", + # :github_advisory_id=>"GHSA-7wpw-2hjm-89gp", + # :cves=>["CVE-2020-28499"], + # :access=>"public", + # :patched_versions=>">=2.1.1", + # :updated=>"2021-03-18T22:54:26.000Z", + # :recommendation=>"Upgrade to version 2.1.1 or later", + # :cwe=>"CWE-915", + # :found_by=>nil, + # :deleted=>nil, + # :id=>1005415, + # :references=> + # "- https://nvd.nist.gov/vuln/detail/CVE-2020-28499\n- https://github.com/yeikos/js.merge/commit/7b0ddc2701d813f2ba289b32d6a4b9d4cc235fb4\n- https://snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1071049\n- https://snyk.io/vuln/SNYK-JS-MERGE-1042987\n- https://vuldb.com/?id.170146\n- https://github.com/yeikos/js.merge/blob/56ca75b2dd0f2820f1e08a49f62f04bbfb8c5f8f/src/index.ts#L64\n- https://github.com/yeikos/js.merge/blob/master/src/index.ts%23L64\n- https://github.com/advisories/GHSA-7wpw-2hjm-89gp", + # :created=>"2021-11-18T16:00:48.538Z", + # :reported_by=>nil, + # :title=>"Prototype Pollution in merge", + # :npm_advisory_id=>nil, + # :overview=>"All versions of package merge <2.1.1 are vulnerable to Prototype Pollution via _recursiveMerge .", + # :url=>"https://github.com/advisories/GHSA-7wpw-2hjm-89gp", + # :line_number=>23} + + # rubocop:enable Layout/LineLength + parsed_issue = { id: id, name: issue[:title], diff --git a/lib/sarif/osv/base_sarif.rb b/lib/sarif/osv/base_sarif.rb index 6ce2c625..07e637e5 100644 --- a/lib/sarif/osv/base_sarif.rb +++ b/lib/sarif/osv/base_sarif.rb @@ -25,6 +25,19 @@ def parse_scan_report! end def parse_issue(issue) + # Example issue + # {"Package"=>"github.com/syncthing/syncthing", + # "Vulnerable Version"=>"0", + # "Version Detected"=>"1.14.0", + # "Patched Version"=>"1.15.0", + # "ID"=>"CVE-2021-21404", + # "Database"=>"Github Advisory Database", + # "Summary"=>"Crash due to malformed relay protocol message", + # "References"=> + # "https://github.com/advisories/GHSA-x462-89pf-6r5h, https://nvd.nist.gov...", + # "Source"=>"https://osv.dev/list", + # "Severity"=>"LOW"} + parsed_issue = { id: issue['ID'], name: SCANNER_NAME, @@ -33,6 +46,7 @@ def parse_issue(issue) messageStrings: { "package": { "text": issue['Package'].to_s }, "title": { "text": issue['Summary'].to_s }, "severity": { "text": issue['Severity'].to_s }, + "cwe": { "text": [issue['ID']].to_s }, "patched_versions": { "text": issue['Patched Version'].to_s }, "vulnerable_versions": { "text": issue['Vulnerable Version'].to_s diff --git a/lib/sarif/pattern_search_sarif.rb b/lib/sarif/pattern_search_sarif.rb index 8d49ff68..c5a97fb5 100644 --- a/lib/sarif/pattern_search_sarif.rb +++ b/lib/sarif/pattern_search_sarif.rb @@ -72,6 +72,10 @@ def parse_issue(issue) return nil if issue[:required] return nil if !issue[:forbidden] + # Example issue + # {:regex=>"Nerv", :forbidden=>true, :required=>false, :msg=>"not important string", + # :hit=>"lance.txt:3:Nerv housed the lance."} + url_info = issue[:hit].split(':') { diff --git a/lib/sarif/repo_not_empty_sarif.rb b/lib/sarif/repo_not_empty_sarif.rb index 763159a9..426200b1 100644 --- a/lib/sarif/repo_not_empty_sarif.rb +++ b/lib/sarif/repo_not_empty_sarif.rb @@ -19,6 +19,9 @@ def parse_scan_report! end def parse_issue(issue) + # Example issue + # {:message=>"Salus was run on a blank directory. This ..."} + { id: "RNE0001", name: "RepositoryIsEmpty", diff --git a/lib/sarif/semgrep_sarif.rb b/lib/sarif/semgrep_sarif.rb index 980899e5..2a88db22 100644 --- a/lib/sarif/semgrep_sarif.rb +++ b/lib/sarif/semgrep_sarif.rb @@ -74,6 +74,11 @@ def message(hit, miss) def parse_hit(hit) return nil if !hit[:forbidden] + # Example hit + # {:id=>"11d6bdec931137a1063338f1f80a631f5b1f2fc2", :pattern=>"$X == $X", :config=>nil, + # :forbidden=>true, :required=>false, :msg=>"Useless equality test.", + # :hit=>"examples/trivial2.py:10: if user.id == user.id:", :severity=>"ERROR"} + location = hit[:hit].split(":") # [file_name, line, code_preview] # location looks like "file.js:123:my_function()" code = if location.size > 3 # code itself has :, like "abc: [xyz]" diff --git a/lib/sarif/trufflehog_sarif.rb b/lib/sarif/trufflehog_sarif.rb index c1d7ca7e..9c865d20 100644 --- a/lib/sarif/trufflehog_sarif.rb +++ b/lib/sarif/trufflehog_sarif.rb @@ -40,6 +40,10 @@ def parse_error(error) def parse_issue(issue) return parse_error(issue) if issue[:scanner_err] + # Example issue + # {"SHA256 of Leaked Credential"=>"REDACTED-SHA", + # "File"=>"url.txt", "Line Num"=>1, "ID"=>"JDBC-PLAIN", "Verified"=>false} + { id: issue['ID'], name: "Leaked credential", diff --git a/lib/sarif/yarn_audit_sarif.rb b/lib/sarif/yarn_audit_sarif.rb index a80b2275..decc2674 100644 --- a/lib/sarif/yarn_audit_sarif.rb +++ b/lib/sarif/yarn_audit_sarif.rb @@ -23,6 +23,17 @@ def parse_issue(issue) return nil if @issues.include?(id) @issues.add(id) + + # Example issue + # {"Package"=>"uglify-js", + # "Patched in"=>">=13.6.6", + # "More info"=>"https://github.com/advisories/GHSA-3p22-ghq8-v749", + # "Severity"=>"low", + # "Title"=>"Renderers can obtain access to random bluetooth device without ...", + # "ID"=>1006709, + # "DectectedVersions"=>["11.5.0"], + # "Dependency of"=>"uglify-js"} + parsed_issue = { id: issue['ID'].to_s, name: issue['Title'], diff --git a/spec/lib/sarif/bandit_sarif_spec.rb b/spec/lib/sarif/bandit_sarif_spec.rb index a732786a..7b2f097f 100644 --- a/spec/lib/sarif/bandit_sarif_spec.rb +++ b/spec/lib/sarif/bandit_sarif_spec.rb @@ -21,7 +21,8 @@ level: "LOW", details: "Consider possible security implications associated with cPickle module.", messageStrings: { "confidence": { "text": "LOW" }, - "severity": { "text": "LOW" } }, + "severity": { "text": "LOW" }, + "cwe": { "text": "[\"CWE-502\"]" } }, properties: { "severity": "LOW" }, start_line: 1, start_column: 1, diff --git a/spec/lib/sarif/brakeman_sarif_spec.rb b/spec/lib/sarif/brakeman_sarif_spec.rb index 6b7466e1..a1b7a10a 100644 --- a/spec/lib/sarif/brakeman_sarif_spec.rb +++ b/spec/lib/sarif/brakeman_sarif_spec.rb @@ -23,7 +23,8 @@ details: "User input in eval", messageStrings: { "title": { "text": "Evaluation" }, "type": { "text": "Dangerous Eval" }, - "warning_code": { "text": "13" } }, + "warning_code": { "text": "13" }, + "cwe": { "text": "[\"CWE-913\", \"CWE-95\"]" } }, start_line: 3, start_column: 1, help_url: "https://brakemanscanner.org/docs/warning_types/dangerous_eval/", diff --git a/spec/lib/sarif/bundle_audit_spec.rb b/spec/lib/sarif/bundle_audit_spec.rb index d6966000..a58e76b4 100644 --- a/spec/lib/sarif/bundle_audit_spec.rb +++ b/spec/lib/sarif/bundle_audit_spec.rb @@ -52,6 +52,7 @@ details = 'There is a possible information disclosure / unintended method' expect(expected_details).to include(details) + # rubocop:disable Layout/LineLength expect(bundle_audit_sarif.parse_issue(issue)).to include( id: "CVE-2021-22885", name: "Possible Information Disclosure / Unintended Method Execution in Action Pack", @@ -61,8 +62,16 @@ start_line: 8, start_column: 1, code: 'actionpack', - properties: { severity: "", detected_versions: ["4.1.15"] } + properties: { severity: "", detected_versions: ["4.1.15"] }, + messageStrings: { cwe: { text: "[\"CVE-2021-22885\"]" }, osvdb: { text: "" }, + package_name: { text: "actionpack" }, + patched_versions: { text: "[\"~> 5.2.4.6\", \"~> 5.2.6\", \"~> 6.0.3, >= 6.0.3.7\", \">= 6.1.3.2\"]" }, + severity: { text: "" }, + title: { text: "Possible Information Disclosure / Unintended Method Execution in Action Pack" }, + type: { text: "UnpatchedGem" }, unaffected_versions: { text: "[\"< 2.0.0\"]" }, + version: { text: "4.1.15" } } ) + # rubocop:enable Layout/LineLength else details = 'There is a possible DoS vulnerability in the Token Authentication logic in' expect(expected_details).to include(details) diff --git a/spec/lib/sarif/cargo_audit_sarif_spec.rb b/spec/lib/sarif/cargo_audit_sarif_spec.rb index 555fcdb6..597f1afa 100644 --- a/spec/lib/sarif/cargo_audit_sarif_spec.rb +++ b/spec/lib/sarif/cargo_audit_sarif_spec.rb @@ -34,6 +34,7 @@ "title": { "text": "MultiDecoder::read() drops uninitialized memory of"\ " arbitrary type on panic in client code" }, "severity": { "text": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" }, + "cwe": { "text": "[\"CVE-2019-15552\"]" }, "patched_versions": { "text": "[\">=0.1.25\"]" }, "unaffected_versions": { "text": "[\"<0.1.14\"]" } }, help_url: "https://github.com/sile/libflate/issues/35", diff --git a/spec/lib/sarif/gosec_sarif_spec.rb b/spec/lib/sarif/gosec_sarif_spec.rb index c318f0f4..190dbd80 100644 --- a/spec/lib/sarif/gosec_sarif_spec.rb +++ b/spec/lib/sarif/gosec_sarif_spec.rb @@ -72,7 +72,7 @@ "https://cwe.mitre.org/data/definitions/798.html", messageStrings: { "severity": { "text": "HIGH" }, "confidence": { "text": "LOW" }, - "cwe": { "text": "https://cwe.mitre.org/data/definitions/798.html" } }, + "cwe": { "text": "[\"CWE-798\"]" } }, start_line: 8, start_column: 2, help_url: "https://cwe.mitre.org/data/definitions/798.html", diff --git a/spec/lib/sarif/osv/go_osv_sarif_spec.rb b/spec/lib/sarif/osv/go_osv_sarif_spec.rb index bd307a21..13a097b9 100644 --- a/spec/lib/sarif/osv/go_osv_sarif_spec.rb +++ b/spec/lib/sarif/osv/go_osv_sarif_spec.rb @@ -46,6 +46,9 @@ def stub_req_with_valid_response "helpUri" => "https://osv.dev/list", "id" => "CVE-2021-21404", "messageStrings" => { + "cwe" => { + "text" => "[\"CVE-2021-21404\"]" + }, "package" => { "text" => "github.com/syncthing/syncthing" }, diff --git a/spec/lib/sarif/osv/gradle_osv_sarif_spec.rb b/spec/lib/sarif/osv/gradle_osv_sarif_spec.rb index 9f3f068b..c00d4da8 100644 --- a/spec/lib/sarif/osv/gradle_osv_sarif_spec.rb +++ b/spec/lib/sarif/osv/gradle_osv_sarif_spec.rb @@ -48,6 +48,9 @@ def stub_req_with_valid_response "helpUri" => "https://osv.dev/list", "id" => "CVE-2020-8908", "messageStrings" => { + "cwe" => { + "text" => "[\"CVE-2020-8908\"]" + }, "package" => { "text" => "com.google.guava:guava" }, diff --git a/spec/lib/sarif/osv/maven_osv_sarif_spec.rb b/spec/lib/sarif/osv/maven_osv_sarif_spec.rb index 96729309..9a28b8f4 100644 --- a/spec/lib/sarif/osv/maven_osv_sarif_spec.rb +++ b/spec/lib/sarif/osv/maven_osv_sarif_spec.rb @@ -48,6 +48,9 @@ def stub_req_with_valid_response "helpUri" => "https://osv.dev/list", "id" => "CVE-2018-15756", "messageStrings" => { + "cwe" => { + "text" => "[\"CVE-2018-15756\"]" + }, "package" => { "text" => "org.springframework:spring-core" }, diff --git a/spec/lib/sarif/osv/python_osv_sarif_spec.rb b/spec/lib/sarif/osv/python_osv_sarif_spec.rb index 71f892d1..c07a8418 100644 --- a/spec/lib/sarif/osv/python_osv_sarif_spec.rb +++ b/spec/lib/sarif/osv/python_osv_sarif_spec.rb @@ -46,6 +46,9 @@ def stub_req_with_valid_response "helpUri" => "https://osv.dev/list", "id" => "CVE-2020-29651", "messageStrings" => { + "cwe" => { + "text" => "[\"CVE-2020-29651\"]" + }, "package" => { "text" => "py" },