Skip to content

Commit 9897939

Browse files
authored
Merge pull request #294 from tushar912/elixir
Elixir Security Importer
2 parents bdf7c85 + 0fa1bf4 commit 9897939

8 files changed

Lines changed: 341 additions & 14 deletions

File tree

AUTHORS.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ The following organizations or individuals have contributed to this repo:
1010
- Ayush Lohani @lohani2280
1111
- Islam Elhakmi @EslamHiko
1212
- Edoardo Lanzini @elanzini
13-
- Navonil Das @NavonilDas
13+
- Navonil Das @NavonilDas
14+
- Tushar Upadhyay @tushar912

SOURCES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,5 @@
4343
+----------------+------------------------------------------------------------------------------------------------------+----------------------------------------------------+
4444
|postgresql | https://www.postgresql.org/support/security/ |postgresql |
4545
+----------------+------------------------------------------------------------------------------------------------------+----------------------------------------------------+
46+
|elixir_security | https://github.com/dependabot/elixir-security-advisories |hex packages |
47+
+----------------+------------------------------------------------------------------------------------------------------+----------------------------------------------------+

vulnerabilities/importer_yielder.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,15 @@
226226
'data_source': 'PostgreSQLDataSource',
227227
'data_source_cfg': {},
228228
},
229+
{
230+
'name': 'elixir_security',
231+
'license': 'cc0-1.0',
232+
'last_run': None,
233+
'data_source': 'ElixirSecurityDataSource',
234+
'data_source_cfg': {
235+
'repository_url': 'https://github.com/dependabot/elixir-security-advisories'
236+
},
237+
},
229238
{
230239
'name': 'apache_tomcat',
231240
'license': '',

vulnerabilities/importers/__init__.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,26 @@
2222

2323

2424
from vulnerabilities.importers.alpine_linux import AlpineDataSource
25+
from vulnerabilities.importers.apache_httpd import ApacheHTTPDDataSource
2526
from vulnerabilities.importers.archlinux import ArchlinuxDataSource
2627
from vulnerabilities.importers.debian import DebianDataSource
27-
from vulnerabilities.importers.npm import NpmDataSource
28-
from vulnerabilities.importers.rust import RustDataSource
29-
from vulnerabilities.importers.safety_db import SafetyDbDataSource
30-
from vulnerabilities.importers.ruby import RubyDataSource
31-
from vulnerabilities.importers.ubuntu import UbuntuDataSource
32-
from vulnerabilities.importers.retiredotnet import RetireDotnetDataSource
33-
from vulnerabilities.importers.suse_backports import SUSEBackportsDataSource
3428
from vulnerabilities.importers.debian_oval import DebianOvalDataSource
35-
from vulnerabilities.importers.redhat import RedhatDataSource
29+
from vulnerabilities.importers.elixir_security import ElixirSecurityDataSource
3630
from vulnerabilities.importers.gentoo import GentooDataSource
37-
from vulnerabilities.importers.openssl import OpenSSLDataSource
38-
from vulnerabilities.importers.ubuntu_usn import UbuntuUSNDataSource
3931
from vulnerabilities.importers.github import GitHubAPIDataSource
40-
from vulnerabilities.importers.nvd import NVDDataSource
41-
from vulnerabilities.importers.project_kb_msr2019 import ProjectKBMSRDataSource
42-
from vulnerabilities.importers.apache_httpd import ApacheHTTPDDataSource
4332
from vulnerabilities.importers.kaybee import KaybeeDataSource
4433
from vulnerabilities.importers.nginx import NginxDataSource
34+
from vulnerabilities.importers.npm import NpmDataSource
35+
from vulnerabilities.importers.nvd import NVDDataSource
36+
from vulnerabilities.importers.openssl import OpenSSLDataSource
4537
from vulnerabilities.importers.postgresql import PostgreSQLDataSource
38+
from vulnerabilities.importers.project_kb_msr2019 import ProjectKBMSRDataSource
39+
from vulnerabilities.importers.redhat import RedhatDataSource
40+
from vulnerabilities.importers.retiredotnet import RetireDotnetDataSource
41+
from vulnerabilities.importers.ruby import RubyDataSource
42+
from vulnerabilities.importers.rust import RustDataSource
43+
from vulnerabilities.importers.safety_db import SafetyDbDataSource
44+
from vulnerabilities.importers.suse_backports import SUSEBackportsDataSource
45+
from vulnerabilities.importers.ubuntu import UbuntuDataSource
46+
from vulnerabilities.importers.ubuntu_usn import UbuntuUSNDataSource
4647
from vulnerabilities.importers.apache_tomcat import ApacheTomcatDataSource
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Copyright (c) nexB Inc. and others. All rights reserved.
2+
# http://nexb.com and https://github.com/nexB/vulnerablecode/
3+
# The VulnerableCode software is licensed under the Apache License version 2.0.
4+
# Data generated with VulnerableCode require an acknowledgment.
5+
#
6+
# You may not use this software except in compliance with the License.
7+
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
8+
# Unless required by applicable law or agreed to in writing, software distributed
9+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
# specific language governing permissions and limitations under the License.
12+
#
13+
# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
14+
# derivative work, you must accompany this data with the following acknowledgment:
15+
#
16+
# Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
17+
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
18+
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
19+
# for any legal advice.
20+
# VulnerableCode is a free software tool from nexB Inc. and others.
21+
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
22+
23+
import asyncio
24+
from typing import List, Set
25+
26+
import yaml
27+
from dephell_specifier import RangeSpecifier
28+
from packageurl import PackageURL
29+
30+
from vulnerabilities.data_source import GitDataSource
31+
from vulnerabilities.data_source import Advisory
32+
from vulnerabilities.data_source import Reference
33+
from vulnerabilities.package_managers import HexVersionAPI
34+
from vulnerabilities.helpers import load_yaml
35+
36+
37+
class ElixirSecurityDataSource(GitDataSource):
38+
def __enter__(self):
39+
super(ElixirSecurityDataSource, self).__enter__()
40+
41+
if not getattr(self, "_added_files", None):
42+
self._added_files, self._updated_files = self.file_changes(
43+
recursive=True, file_ext="yml", subdir="./packages"
44+
)
45+
self.pkg_manager_api = HexVersionAPI()
46+
self.set_api(self.collect_packages())
47+
48+
def set_api(self, packages):
49+
asyncio.run(self.pkg_manager_api.load_api(packages))
50+
51+
def updated_advisories(self) -> Set[Advisory]:
52+
files = self._updated_files
53+
advisories = []
54+
for f in files:
55+
processed_data = self.process_file(f)
56+
if processed_data:
57+
advisories.append(processed_data)
58+
return self.batch_advisories(advisories)
59+
60+
def added_advisories(self) -> Set[Advisory]:
61+
files = self._added_files
62+
advisories = []
63+
for f in files:
64+
processed_data = self.process_file(f)
65+
if processed_data:
66+
advisories.append(processed_data)
67+
return self.batch_advisories(advisories)
68+
69+
def collect_packages(self):
70+
packages = set()
71+
files = self._updated_files.union(self._added_files)
72+
for f in files:
73+
data = load_yaml(f)
74+
if data.get("package"):
75+
packages.add(data["package"])
76+
77+
return packages
78+
79+
def get_versions_for_pkg_from_range_list(self, version_range_list, pkg_name):
80+
# Takes a list of version ranges(pathced and unaffected) of a package
81+
# as parameter and returns a tuple of safe package versions and
82+
# vulnerable package versions
83+
84+
safe_pkg_versions = []
85+
vuln_pkg_versions = []
86+
all_version_list = self.pkg_manager_api.get(pkg_name)
87+
if not version_range_list:
88+
return [], all_version_list
89+
version_ranges = {RangeSpecifier(r) for r in version_range_list}
90+
for version in all_version_list:
91+
if any([version in v for v in version_ranges]):
92+
safe_pkg_versions.append(version)
93+
94+
vuln_pkg_versions = set(all_version_list) - set(safe_pkg_versions)
95+
return safe_pkg_versions, vuln_pkg_versions
96+
97+
def process_file(self, path):
98+
yaml_file = load_yaml(path)
99+
pkg_name = yaml_file["package"]
100+
safe_pkg_versions = []
101+
vuln_pkg_versions = []
102+
if not yaml_file.get("patched_versions"):
103+
yaml_file["patched_versions"] = []
104+
105+
if not yaml_file.get("unaffected_versions"):
106+
yaml_file["unaffected_versions"] = []
107+
108+
safe_pkg_versions, vuln_pkg_versions = self.get_versions_for_pkg_from_range_list(
109+
yaml_file["patched_versions"] + yaml_file["unaffected_versions"],
110+
pkg_name,
111+
)
112+
113+
if yaml_file.get("cve"):
114+
cve_id = "CVE-" + yaml_file["cve"]
115+
else:
116+
cve_id = ""
117+
118+
safe_purls = []
119+
vuln_purls = []
120+
121+
safe_purls = {
122+
PackageURL(name=pkg_name, type="hex", version=version) for version in safe_pkg_versions
123+
}
124+
125+
vuln_purls = {
126+
PackageURL(name=pkg_name, type="hex", version=version) for version in vuln_pkg_versions
127+
}
128+
129+
vuln_references = [
130+
Reference(
131+
reference_id=yaml_file["id"],
132+
),
133+
Reference(
134+
url=yaml_file["link"],
135+
),
136+
]
137+
138+
return Advisory(
139+
summary=yaml_file["description"],
140+
impacted_package_urls=vuln_purls,
141+
resolved_package_urls=safe_purls,
142+
cve_id=cve_id,
143+
vuln_references=vuln_references,
144+
)

vulnerabilities/package_managers.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,24 @@ async def fetch(self, owner_repo: str, session) -> None:
351351
resp = await session.request(method="GET", url=endpoint)
352352
resp = await resp.json()
353353
self.cache[owner_repo] = [release["ref"].split("/")[-1] for release in resp]
354+
355+
356+
class HexVersionAPI(VersionAPI):
357+
async def load_api(self, pkg_set):
358+
async with ClientSession(raise_for_status=True) as session:
359+
await asyncio.gather(
360+
*[self.fetch(pkg, session) for pkg in pkg_set if pkg not in self.cache]
361+
)
362+
363+
async def fetch(self, pkg, session):
364+
url = f"https://hex.pm/api/packages/{pkg}"
365+
versions = set()
366+
try:
367+
response = await session.request(method="GET", url=url)
368+
response = await response.json()
369+
for release in response["releases"]:
370+
versions.add(release["version"])
371+
except (ClientResponseError, JSONDecodeError):
372+
pass
373+
374+
self.cache[pkg] = versions
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
id: 2aae6e3a-24a3-4d5f-86ff-b964eaf7c6d1
3+
package: coherence
4+
disclosure_date: 2017-08-02
5+
cve: 2018-20301
6+
link: https://github.com/smpallen99/coherence/issues/270
7+
title: |
8+
Permissive parameters and privilege escalation
9+
description: |
10+
The Coherence library has "Mass Assignment"-like vulnerabilities.
11+
patched_versions:
12+
- ">= 0.5.2"
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Copyright (c) nexB Inc. and others. All rights reserved.
2+
# http://nexb.com and https://github.com/nexB/vulnerablecode/
3+
# The VulnerableCode software is licensed under the Apache License version 2.0.
4+
# Data generated with VulnerableCode require an acknowledgment.
5+
#
6+
# You may not use this software except in compliance with the License.
7+
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
8+
# Unless required by applicable law or agreed to in writing, software distributed
9+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
# specific language governing permissions and limitations under the License.
12+
#
13+
# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
14+
# derivative work, you must accompany this data with the following acknowledgment:
15+
#
16+
# Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
17+
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
18+
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
19+
# for any legal advice.
20+
# VulnerableCode is a free software tool from nexB Inc. and others.
21+
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
22+
23+
import os
24+
from collections import OrderedDict
25+
from unittest import TestCase
26+
27+
from packageurl import PackageURL
28+
29+
from vulnerabilities.data_source import Advisory
30+
from vulnerabilities.data_source import Reference
31+
from vulnerabilities.importers.elixir_security import ElixirSecurityDataSource
32+
from vulnerabilities.package_managers import HexVersionAPI
33+
34+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
35+
36+
37+
class TestElixirSecurityDataSource(TestCase):
38+
@classmethod
39+
def setUpClass(cls):
40+
data_source_cfg = {
41+
"repository_url": "https://github.com/dependabot/elixir-security-advisories",
42+
}
43+
cls.data_src = ElixirSecurityDataSource(1, config=data_source_cfg)
44+
cls.data_src.pkg_manager_api = HexVersionAPI(
45+
{
46+
"coherence": [
47+
"0.5.2",
48+
"0.5.1",
49+
"0.5.0",
50+
"0.4.0",
51+
"0.3.1",
52+
"0.3.0",
53+
"0.2.0",
54+
"0.1.3",
55+
"0.1.2",
56+
"0.1.1",
57+
"0.1.0",
58+
]
59+
}
60+
)
61+
62+
def test_process_file(self):
63+
64+
path = os.path.join(BASE_DIR, "test_data/elixir_security/test_file.yml")
65+
expected_data = Advisory(
66+
summary=('The Coherence library has "Mass Assignment"-like vulnerabilities.\n'),
67+
impacted_package_urls={
68+
PackageURL(
69+
type="hex",
70+
name="coherence",
71+
version="0.5.1",
72+
),
73+
PackageURL(
74+
type="hex",
75+
name="coherence",
76+
version="0.5.0",
77+
),
78+
PackageURL(
79+
type="hex",
80+
name="coherence",
81+
version="0.4.0",
82+
),
83+
PackageURL(
84+
type="hex",
85+
name="coherence",
86+
version="0.3.1",
87+
),
88+
PackageURL(
89+
type="hex",
90+
name="coherence",
91+
version="0.3.0",
92+
),
93+
PackageURL(
94+
type="hex",
95+
name="coherence",
96+
version="0.2.0",
97+
),
98+
PackageURL(
99+
type="hex",
100+
name="coherence",
101+
version="0.1.3",
102+
),
103+
PackageURL(
104+
type="hex",
105+
name="coherence",
106+
version="0.1.2",
107+
),
108+
PackageURL(
109+
type="hex",
110+
name="coherence",
111+
version="0.1.1",
112+
),
113+
PackageURL(
114+
type="hex",
115+
name="coherence",
116+
version="0.1.0",
117+
),
118+
},
119+
resolved_package_urls={
120+
PackageURL(
121+
type="hex",
122+
name="coherence",
123+
version="0.5.2",
124+
),
125+
},
126+
vuln_references=[
127+
Reference(
128+
reference_id="2aae6e3a-24a3-4d5f-86ff-b964eaf7c6d1",
129+
),
130+
Reference(url="https://github.com/smpallen99/coherence/issues/270"),
131+
],
132+
cve_id="CVE-2018-20301",
133+
)
134+
135+
found_data = self.data_src.process_file(path)
136+
137+
assert expected_data == found_data

0 commit comments

Comments
 (0)