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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2.22.4
uses: github/codeql-action/init@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
Expand All @@ -76,4 +76,4 @@ jobs:
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@49abf0ba24d0b7953cb586944e918a0b92074c80 # v2.22.4
uses: github/codeql-action/analyze@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5
4 changes: 2 additions & 2 deletions .github/workflows/fuzzing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:
if: github.event.repository.fork == false
steps:
- name: Check out code
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: 3.9

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/spelling.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ jobs:
egress-policy: audit

- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: check-spelling/check-spelling@d7cd2973c513e84354f9d6cf50a6417a628a78ce # v0.0.21
- uses: check-spelling/[email protected].22
with:
post_comment: '0'
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ repos:
exclude: ^fuzz/generated/

- repo: https://github.com/psf/black-pre-commit-mirror
rev: 23.9.1
rev: 23.10.1
hooks:
- id: black
exclude: ^fuzz/generated/

- repo: https://github.com/asottile/pyupgrade
rev: v3.10.1
rev: v3.15.0
hooks:
- id: pyupgrade
exclude: ^fuzz/generated/
Expand All @@ -37,7 +37,7 @@ repos:
- id: gitlint

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.5.1
rev: v1.6.1
hooks:
- id: mypy
additional_dependencies:
Expand Down
7 changes: 7 additions & 0 deletions cve_bin_tool/data_sources/curl_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@


class Curl_Source(Data_Source):
"""Represents a data source for retrieving information about vulnerabilities in cURL."""

SOURCE = "Curl"
CACHEDIR = DISK_LOCATION_DEFAULT
BACKUPCACHEDIR = DISK_LOCATION_BACKUP
LOGGER = LOGGER.getChild("CVEDB")
DATA_SOURCE_LINK = "https://curl.se/docs/vuln.json"

def __init__(self, error_mode=ErrorMode.TruncTrace):
"""Initialize a Curl_Source instance. Args: error_mode (ErrorMode): The error mode to be used."""
self.cve_list = None
self.cachedir = self.CACHEDIR
self.backup_cachedir = self.BACKUPCACHEDIR
Expand All @@ -40,12 +43,14 @@ def __init__(self, error_mode=ErrorMode.TruncTrace):
self.vulnerability_data = []

async def get_cve_data(self):
"""Get cURL vulnerability data. Fetches the cURL vulnerability data and retrieves a list of affected data."""
await self.fetch_cves()
self.get_cve_list()

return (None, self.affected_data), self.source_name

async def fetch_cves(self):
"""Fetch cURL vulnerabilities data."""
if not self.session:
connector = aiohttp.TCPConnector(limit_per_host=19)
self.session = RateLimiter(
Expand All @@ -57,6 +62,7 @@ async def fetch_cves(self):
await self.session.close()

async def download_curl_vulnerabilities(self, session: RateLimiter) -> None:
"""Download cURL vulnerability data and save it to a file. Args: session (RateLimiter): The session to use for the HTTP request."""
async with await session.get(self.DATA_SOURCE_LINK) as response:
response.raise_for_status()
self.vulnerability_data = await response.json()
Expand All @@ -66,6 +72,7 @@ async def download_curl_vulnerabilities(self, session: RateLimiter) -> None:
await f.write(json.dumps(self.vulnerability_data, indent=4))

def get_cve_list(self):
"""Get a list of affected cURL vulnerabilities."""
self.affected_data = []

for cve in self.vulnerability_data:
Expand Down
5 changes: 5 additions & 0 deletions cve_bin_tool/data_sources/gad_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@


class GAD_Source(Data_Source):
"""Represents a data source for retrieving Common Vulnerabilities and Exposures (CVEs) from GitLab Advisory Database (GAD)."""

SOURCE = "GAD"
CACHEDIR = DISK_LOCATION_DEFAULT
LOGGER = LOGGER.getChild("CVEDB")
Expand Down Expand Up @@ -174,6 +176,9 @@ async def update_cve_entries(self):
self.all_cve_entries.append(data)

def parse_multiple_version(self, range_string):
"""Parses multiple version strings from a range string.
Args:range_string (str): The range string to parse.
Returns:list: A list of parsed version strings."""
version_strings = range_string.split(",")
start = False
versions = []
Expand Down
21 changes: 12 additions & 9 deletions cve_bin_tool/data_sources/osv_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,15 +292,18 @@ def format_data(self, all_cve_entries):

severity_data.append(cve)

for package in cve_item["affected"]:
product = package["package"]["name"]
for package_data in cve_item.get("affected", []):
package = package_data.get("package", {})
if not package:
continue

product = package.get("name")
vendor = (
"unknown" # OSV Schema does not provide vendor names for packages
)
if (
"github.com/" in product
): # if package name is of format github.com/xxxx/yyyy xxxx can be vendor name and yyyy is package name
vendor = product.split("/")[-2] # trying to guess vendor name

if product.startswith("github.com/"):

Check failure

Code scanning / CodeQL

Incomplete URL substring sanitization

The string [github.com/](1) may be at an arbitrary position in the sanitized URL.
vendor = product.split("/")[-2]
product = product.split("/")[-1]

affected = {
Expand All @@ -315,12 +318,12 @@ def format_data(self, all_cve_entries):
}

events = None
for ranges in package.get("ranges", []):
for ranges in package_data.get("ranges", []):
if ranges["type"] == "SEMVER":
events = ranges["events"]

if events is None and "versions" in package:
versions = package["versions"]
if events is None and "versions" in package_data:
versions = package_data["versions"]

if versions == []:
continue
Expand Down
47 changes: 47 additions & 0 deletions cve_bin_tool/output_engine/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,10 +594,51 @@ def output_pdf(
exploits: bool = False,
all_product_data=None,
):
"""Output a PDF of CVEs
Required module: Reportlab not found"""
LOGGER.warning("PDF output requires install of reportlab")


class OutputEngine:
"""
Class represention of OutputEngine
Attributes:
all_cve_data (dict[ProductInfo, CVEData])
scanned_dir (str)
filename (str)
themes_dir (str)
time_of_last_update
tag (str)
logger
products_with_cve (int)
products_without_cve (int)
total_files (int)
is_report (bool)
no_zero_cve_report (bool)
append
merge_report
affected_versions (int)
all_cve_version_info
detailed (bool)
vex_filename (str)
exploits (bool)
all_product_data
sbom_filename (str)
sbom_type (str)
sbom_format (str)
sbom_root (str)
offline (bool)

Methods:
output_cves: Output a list of CVEs to other formats like CSV or JSON.
generate_vex: Generate a vex file and create vulnerability entry.
generate_sbom: Create SBOM package and generate SBOM file.
output_file_wrapper:
output_file: Generate a file for list of CVE
check_file_path: Generate a new filename if file already exists.
check_dir_path: Generate a new filename if filepath is a directory.
"""

def __init__(
self,
all_cve_data: dict[ProductInfo, CVEData],
Expand Down Expand Up @@ -626,6 +667,7 @@ def __init__(
sbom_root: str = "CVE_SBOM",
offline: bool = False,
):
"""Constructor for OutputEngine class."""
self.logger = logger or LOGGER.getChild(self.__class__.__name__)
self.all_cve_version_info = all_cve_version_info
self.scanned_dir = scanned_dir
Expand Down Expand Up @@ -735,6 +777,7 @@ def output_cves(self, outfile, output_type="console"):
)

def generate_vex(self, all_cve_data: dict[ProductInfo, CVEData], filename: str):
"""Generate a vex file and create vulnerability entry."""
analysis_state = {
Remarks.NewFound: "in_triage",
Remarks.Unexplored: "in_triage",
Expand Down Expand Up @@ -840,6 +883,7 @@ def generate_sbom(
sbom_format="tag",
sbom_root="CVE-SCAN",
):
"""Create SBOM package and generate SBOM file."""
# Create SBOM
sbom_packages = {}
sbom_relationships = []
Expand Down Expand Up @@ -895,6 +939,7 @@ def generate_sbom(
my_generator.generate(parent, my_sbom.get_sbom(), filename=filename)

def output_file_wrapper(self, output_types=["console"]):
"""Call output_file method for all output types."""
for output_type in output_types:
self.output_file(output_type)

Expand Down Expand Up @@ -959,6 +1004,7 @@ def output_file(self, output_type="console"):
self.output_cves(f, output_type)

def check_file_path(self, filepath: str, output_type: str, prefix: str = "output"):
"""Generate a new filename if file already exists."""
# check if the file already exists
if Path(filepath).is_file():
self.logger.warning(f"Failed to write at '{filepath}'. File already exists")
Expand All @@ -970,6 +1016,7 @@ def check_file_path(self, filepath: str, output_type: str, prefix: str = "output
def check_dir_path(
self, filepath: str, output_type: str, prefix: str = "intermediate"
):
"""Generate a new filename if filepath is a directory."""
if Path(filepath).is_dir():
self.logger.info(
f"Generating a new filename with Default Naming Convention in directory path {filepath}"
Expand Down
6 changes: 3 additions & 3 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
black==23.9.1
black==23.10.1
isort; python_version < "3.8"
isort==5.12.0; python_version >= "3.8"
pre-commit; python_version < "3.8"
pre-commit==3.4.0; python_version >= "3.8"
pre-commit==3.5.0; python_version >= "3.8"
flake8; python_version < "3.8"
flake8==6.1.0; python_version >= "3.8"
bandit==1.7.5
gitlint==v0.19.1
interrogate
mypy==v1.5.1
mypy==v1.6.1
pytest>=7.2.0
pytest-xdist
pytest-cov
Expand Down