Skip to content
Merged
3 changes: 2 additions & 1 deletion AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ The following organizations or individuals have contributed to this repo:
- Ayush Lohani @lohani2280
- Islam Elhakmi @EslamHiko
- Edoardo Lanzini @elanzini
- Navonil Das @NavonilDas
- Navonil Das @NavonilDas
- Tushar Upadhyay @tushar912
2 changes: 2 additions & 0 deletions SOURCES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@
+----------------+------------------------------------------------------------------------------------------------------+----------------------------------------------------+
|postgresql | https://www.postgresql.org/support/security/ |postgresql |
+----------------+------------------------------------------------------------------------------------------------------+----------------------------------------------------+
|elixir_security | https://github.com/dependabot/elixir-security-advisories |hex packages |
+----------------+------------------------------------------------------------------------------------------------------+----------------------------------------------------+
9 changes: 9 additions & 0 deletions vulnerabilities/importer_yielder.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,15 @@
'data_source': 'PostgreSQLDataSource',
'data_source_cfg': {},
},
{
'name': 'elixir_security',
'license': 'cc0-1.0',
'last_run': None,
'data_source': 'ElixirSecurityDataSource',
'data_source_cfg': {
'repository_url': 'https://github.com/dependabot/elixir-security-advisories'
},
},
{
'name': 'apache_tomcat',
'license': '',
Expand Down
27 changes: 14 additions & 13 deletions vulnerabilities/importers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,26 @@


from vulnerabilities.importers.alpine_linux import AlpineDataSource
from vulnerabilities.importers.apache_httpd import ApacheHTTPDDataSource
from vulnerabilities.importers.archlinux import ArchlinuxDataSource
from vulnerabilities.importers.debian import DebianDataSource
from vulnerabilities.importers.npm import NpmDataSource
from vulnerabilities.importers.rust import RustDataSource
from vulnerabilities.importers.safety_db import SafetyDbDataSource
from vulnerabilities.importers.ruby import RubyDataSource
from vulnerabilities.importers.ubuntu import UbuntuDataSource
from vulnerabilities.importers.retiredotnet import RetireDotnetDataSource
from vulnerabilities.importers.suse_backports import SUSEBackportsDataSource
from vulnerabilities.importers.debian_oval import DebianOvalDataSource
from vulnerabilities.importers.redhat import RedhatDataSource
from vulnerabilities.importers.elixir_security import ElixirSecurityDataSource
from vulnerabilities.importers.gentoo import GentooDataSource
from vulnerabilities.importers.openssl import OpenSSLDataSource
from vulnerabilities.importers.ubuntu_usn import UbuntuUSNDataSource
from vulnerabilities.importers.github import GitHubAPIDataSource
from vulnerabilities.importers.nvd import NVDDataSource
from vulnerabilities.importers.project_kb_msr2019 import ProjectKBMSRDataSource
from vulnerabilities.importers.apache_httpd import ApacheHTTPDDataSource
from vulnerabilities.importers.kaybee import KaybeeDataSource
from vulnerabilities.importers.nginx import NginxDataSource
from vulnerabilities.importers.npm import NpmDataSource
from vulnerabilities.importers.nvd import NVDDataSource
from vulnerabilities.importers.openssl import OpenSSLDataSource
from vulnerabilities.importers.postgresql import PostgreSQLDataSource
from vulnerabilities.importers.project_kb_msr2019 import ProjectKBMSRDataSource
from vulnerabilities.importers.redhat import RedhatDataSource
from vulnerabilities.importers.retiredotnet import RetireDotnetDataSource
from vulnerabilities.importers.ruby import RubyDataSource
from vulnerabilities.importers.rust import RustDataSource
from vulnerabilities.importers.safety_db import SafetyDbDataSource
from vulnerabilities.importers.suse_backports import SUSEBackportsDataSource
from vulnerabilities.importers.ubuntu import UbuntuDataSource
from vulnerabilities.importers.ubuntu_usn import UbuntuUSNDataSource
from vulnerabilities.importers.apache_tomcat import ApacheTomcatDataSource
144 changes: 144 additions & 0 deletions vulnerabilities/importers/elixir_security.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Copyright (c) nexB Inc. and others. All rights reserved.
# http://nexb.com and https://github.com/nexB/vulnerablecode/
# The VulnerableCode software is licensed under the Apache License version 2.0.
# Data generated with VulnerableCode require an acknowledgment.
#
# You may not use this software except in compliance with the License.
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
#
# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
# derivative work, you must accompany this data with the following acknowledgment:
#
# Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
# for any legal advice.
# VulnerableCode is a free software tool from nexB Inc. and others.
# Visit https://github.com/nexB/vulnerablecode/ for support and download.

import asyncio
from typing import List, Set

import yaml
from dephell_specifier import RangeSpecifier
from packageurl import PackageURL

from vulnerabilities.data_source import GitDataSource
from vulnerabilities.data_source import Advisory
from vulnerabilities.data_source import Reference
from vulnerabilities.package_managers import HexVersionAPI
from vulnerabilities.helpers import load_yaml


class ElixirSecurityDataSource(GitDataSource):
def __enter__(self):
super(ElixirSecurityDataSource, self).__enter__()

if not getattr(self, "_added_files", None):
self._added_files, self._updated_files = self.file_changes(
recursive=True, file_ext="yml", subdir="./packages"
)
self.pkg_manager_api = HexVersionAPI()
self.set_api(self.collect_packages())

def set_api(self, packages):
asyncio.run(self.pkg_manager_api.load_api(packages))

def updated_advisories(self) -> Set[Advisory]:
files = self._updated_files
advisories = []
for f in files:
processed_data = self.process_file(f)
if processed_data:
advisories.append(processed_data)
return self.batch_advisories(advisories)

def added_advisories(self) -> Set[Advisory]:
files = self._added_files
advisories = []
for f in files:
processed_data = self.process_file(f)
if processed_data:
advisories.append(processed_data)
return self.batch_advisories(advisories)

def collect_packages(self):
packages = set()
files = self._updated_files.union(self._added_files)
for f in files:
data = load_yaml(f)
if data.get("package"):
packages.add(data["package"])

return packages

def get_versions_for_pkg_from_range_list(self, version_range_list, pkg_name):
# Takes a list of version ranges(pathced and unaffected) of a package
# as parameter and returns a tuple of safe package versions and
# vulnerable package versions

safe_pkg_versions = []
vuln_pkg_versions = []
all_version_list = self.pkg_manager_api.get(pkg_name)
if not version_range_list:
return [], all_version_list
version_ranges = {RangeSpecifier(r) for r in version_range_list}
for version in all_version_list:
if any([version in v for v in version_ranges]):
safe_pkg_versions.append(version)

vuln_pkg_versions = set(all_version_list) - set(safe_pkg_versions)
return safe_pkg_versions, vuln_pkg_versions

def process_file(self, path):
yaml_file = load_yaml(path)
pkg_name = yaml_file["package"]
safe_pkg_versions = []
vuln_pkg_versions = []
if not yaml_file.get("patched_versions"):
yaml_file["patched_versions"] = []

if not yaml_file.get("unaffected_versions"):
yaml_file["unaffected_versions"] = []

safe_pkg_versions, vuln_pkg_versions = self.get_versions_for_pkg_from_range_list(
yaml_file["patched_versions"] + yaml_file["unaffected_versions"],
pkg_name,
)

if yaml_file.get("cve"):
cve_id = "CVE-" + yaml_file["cve"]
else:
cve_id = ""

safe_purls = []
vuln_purls = []

safe_purls = {
PackageURL(name=pkg_name, type="hex", version=version) for version in safe_pkg_versions
}

vuln_purls = {
PackageURL(name=pkg_name, type="hex", version=version) for version in vuln_pkg_versions
}

vuln_references = [
Reference(
reference_id=yaml_file["id"],
),
Reference(
url=yaml_file["link"],
),
]

return Advisory(
summary=yaml_file["description"],
impacted_package_urls=vuln_purls,
resolved_package_urls=safe_purls,
cve_id=cve_id,
vuln_references=vuln_references,
)
21 changes: 21 additions & 0 deletions vulnerabilities/package_managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,24 @@ async def fetch(self, owner_repo: str, session) -> None:
resp = await session.request(method="GET", url=endpoint)
resp = await resp.json()
self.cache[owner_repo] = [release["ref"].split("/")[-1] for release in resp]


class HexVersionAPI(VersionAPI):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

async def load_api(self, pkg_set):
async with ClientSession(raise_for_status=True) as session:
await asyncio.gather(
*[self.fetch(pkg, session) for pkg in pkg_set if pkg not in self.cache]
)

async def fetch(self, pkg, session):
url = f"https://hex.pm/api/packages/{pkg}"
versions = set()
try:
response = await session.request(method="GET", url=url)
response = await response.json()
for release in response["releases"]:
versions.add(release["version"])
except (ClientResponseError, JSONDecodeError):
pass

self.cache[pkg] = versions
12 changes: 12 additions & 0 deletions vulnerabilities/tests/test_data/elixir_security/test_file.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
id: 2aae6e3a-24a3-4d5f-86ff-b964eaf7c6d1
package: coherence
disclosure_date: 2017-08-02
cve: 2018-20301
link: https://github.com/smpallen99/coherence/issues/270
title: |
Permissive parameters and privilege escalation
description: |
The Coherence library has "Mass Assignment"-like vulnerabilities.
patched_versions:
- ">= 0.5.2"
137 changes: 137 additions & 0 deletions vulnerabilities/tests/test_elixir_security.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Copyright (c) nexB Inc. and others. All rights reserved.
# http://nexb.com and https://github.com/nexB/vulnerablecode/
# The VulnerableCode software is licensed under the Apache License version 2.0.
# Data generated with VulnerableCode require an acknowledgment.
#
# You may not use this software except in compliance with the License.
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
#
# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
# derivative work, you must accompany this data with the following acknowledgment:
#
# Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
# for any legal advice.
# VulnerableCode is a free software tool from nexB Inc. and others.
# Visit https://github.com/nexB/vulnerablecode/ for support and download.

import os
from collections import OrderedDict
from unittest import TestCase

from packageurl import PackageURL

from vulnerabilities.data_source import Advisory
from vulnerabilities.data_source import Reference
from vulnerabilities.importers.elixir_security import ElixirSecurityDataSource
from vulnerabilities.package_managers import HexVersionAPI

BASE_DIR = os.path.dirname(os.path.abspath(__file__))


class TestElixirSecurityDataSource(TestCase):
@classmethod
def setUpClass(cls):
data_source_cfg = {
"repository_url": "https://github.com/dependabot/elixir-security-advisories",
}
cls.data_src = ElixirSecurityDataSource(1, config=data_source_cfg)
cls.data_src.pkg_manager_api = HexVersionAPI(
{
"coherence": [
"0.5.2",
"0.5.1",
"0.5.0",
"0.4.0",
"0.3.1",
"0.3.0",
"0.2.0",
"0.1.3",
"0.1.2",
"0.1.1",
"0.1.0",
]
}
)

def test_process_file(self):

path = os.path.join(BASE_DIR, "test_data/elixir_security/test_file.yml")
expected_data = Advisory(
summary=('The Coherence library has "Mass Assignment"-like vulnerabilities.\n'),
impacted_package_urls={
PackageURL(
type="hex",
name="coherence",
version="0.5.1",
),
PackageURL(
type="hex",
name="coherence",
version="0.5.0",
),
PackageURL(
type="hex",
name="coherence",
version="0.4.0",
),
PackageURL(
type="hex",
name="coherence",
version="0.3.1",
),
PackageURL(
type="hex",
name="coherence",
version="0.3.0",
),
PackageURL(
type="hex",
name="coherence",
version="0.2.0",
),
PackageURL(
type="hex",
name="coherence",
version="0.1.3",
),
PackageURL(
type="hex",
name="coherence",
version="0.1.2",
),
PackageURL(
type="hex",
name="coherence",
version="0.1.1",
),
PackageURL(
type="hex",
name="coherence",
version="0.1.0",
),
},
resolved_package_urls={
PackageURL(
type="hex",
name="coherence",
version="0.5.2",
),
},
vuln_references=[
Reference(
reference_id="2aae6e3a-24a3-4d5f-86ff-b964eaf7c6d1",
),
Reference(url="https://github.com/smpallen99/coherence/issues/270"),
],
cve_id="CVE-2018-20301",
)

found_data = self.data_src.process_file(path)

assert expected_data == found_data