Skip to content
Open
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
469 changes: 469 additions & 0 deletions vulnerabilities/importers/osv_v2.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 4.2.25 on 2025-12-24 07:04

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("vulnerabilities", "0106_alter_advisoryreference_url_and_more"),
]

operations = [
migrations.AlterField(
model_name="advisoryseverity",
name="scoring_elements",
field=models.CharField(
help_text="Supporting scoring elements used to compute the score values. For example a CVSS vector string as used to compute a CVSS score.",
max_length=200,
null=True,
),
),
]
2 changes: 1 addition & 1 deletion vulnerabilities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2577,7 +2577,7 @@ class AdvisorySeverity(models.Model):
value = models.CharField(max_length=50, help_text="Example: 9.0, Important, High", null=True)

scoring_elements = models.CharField(
max_length=150,
max_length=200,
null=True,
help_text="Supporting scoring elements used to compute the score values. "
"For example a CVSS vector string as used to compute a CVSS score.",
Expand Down
5 changes: 2 additions & 3 deletions vulnerabilities/pipelines/v2_importers/github_osv_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from fetchcode.vcs import fetch_via_vcs

from vulnerabilities.importer import AdvisoryData
from vulnerabilities.importers.osv_v2 import parse_advisory_data_v3
from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2
from vulnerabilities.utils import get_advisory_url

Expand Down Expand Up @@ -47,8 +48,6 @@ def advisories_count(self):
return sum(1 for _ in advisory_dir.rglob("*.json"))

def collect_advisories(self) -> Iterable[AdvisoryData]:
from vulnerabilities.importers.osv import parse_advisory_data_v2

supported_ecosystems = [
"pypi",
"npm",
Expand All @@ -72,7 +71,7 @@ def collect_advisories(self) -> Iterable[AdvisoryData]:
with open(file) as f:
raw_data = json.load(f)
advisory_text = file.read_text()
yield parse_advisory_data_v2(
yield parse_advisory_data_v3(
raw_data=raw_data,
supported_ecosystems=supported_ecosystems,
advisory_url=advisory_url,
Expand Down
5 changes: 2 additions & 3 deletions vulnerabilities/pipelines/v2_importers/oss_fuzz.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from fetchcode.vcs import fetch_via_vcs

from vulnerabilities.importer import AdvisoryData
from vulnerabilities.importers.osv_v2 import parse_advisory_data_v3
from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2
from vulnerabilities.utils import get_advisory_url

Expand Down Expand Up @@ -43,8 +44,6 @@ def advisories_count(self):
return sum(1 for _ in vulns_directory.rglob("*.yaml"))

def collect_advisories(self) -> Iterable[AdvisoryData]:
from vulnerabilities.importers.osv import parse_advisory_data_v2

base_directory = Path(self.vcs_response.dest_dir)
vulns_directory = base_directory / "vulns"

Expand All @@ -56,7 +55,7 @@ def collect_advisories(self) -> Iterable[AdvisoryData]:
)
advisory_text = advisory.read_text()
advisory_dict = saneyaml.load(advisory_text)
yield parse_advisory_data_v2(
yield parse_advisory_data_v3(
raw_data=advisory_dict,
supported_ecosystems=["generic"],
advisory_url=advisory_url,
Expand Down
5 changes: 2 additions & 3 deletions vulnerabilities/pipelines/v2_importers/pypa_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from fetchcode.vcs import fetch_via_vcs

from vulnerabilities.importer import AdvisoryData
from vulnerabilities.importers.osv_v2 import parse_advisory_data_v3
from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2
from vulnerabilities.utils import get_advisory_url

Expand Down Expand Up @@ -46,8 +47,6 @@ def advisories_count(self):
return sum(1 for _ in vulns_directory.rglob("*.yaml"))

def collect_advisories(self) -> Iterable[AdvisoryData]:
from vulnerabilities.importers.osv import parse_advisory_data_v2

base_directory = Path(self.vcs_response.dest_dir)
vulns_directory = base_directory / "vulns"

Expand All @@ -59,7 +58,7 @@ def collect_advisories(self) -> Iterable[AdvisoryData]:
)
advisory_text = advisory.read_text()
advisory_dict = saneyaml.load(advisory_text)
yield parse_advisory_data_v2(
yield parse_advisory_data_v3(
raw_data=advisory_dict,
supported_ecosystems=["pypi"],
advisory_url=advisory_url,
Expand Down
4 changes: 2 additions & 2 deletions vulnerabilities/pipelines/v2_importers/pysec_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import requests

from vulnerabilities.importer import AdvisoryData
from vulnerabilities.importers.osv_v2 import parse_advisory_data_v3
from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2


Expand Down Expand Up @@ -47,7 +48,6 @@ def advisories_count(self) -> int:

def collect_advisories(self) -> Iterable[AdvisoryData]:
"""Yield AdvisoryData using a zipped data dump of OSV data"""
from vulnerabilities.importers.osv import parse_advisory_data_v2

with ZipFile(BytesIO(self.advisory_zip)) as zip_file:
for file_name in zip_file.namelist():
Expand All @@ -60,7 +60,7 @@ def collect_advisories(self) -> Iterable[AdvisoryData]:
with zip_file.open(file_name) as f:
vul_info = json.load(f)
advisory_text = f.read()
yield parse_advisory_data_v2(
yield parse_advisory_data_v3(
raw_data=vul_info,
supported_ecosystems=["pypi"],
advisory_url=self.url,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ def test_collect_advisories(mock_pathlib, mock_vcs_response, mock_fetch_via_vcs)
mock_vcs_response.dest_dir = str(mock_pathlib.parent)

# Mock `parse_advisory_data` to return an AdvisoryData object
with patch("vulnerabilities.importers.osv.parse_advisory_data_v2") as mock_parse:
with patch(
"vulnerabilities.pipelines.v2_importers.pypa_importer.parse_advisory_data_v3"
) as mock_parse:
mock_parse.return_value = AdvisoryData(
advisory_id="CVE-2021-1234",
summary="Sample PyPI vulnerability",
Expand Down Expand Up @@ -149,7 +151,9 @@ def test_collect_advisories_with_invalid_yaml(mock_pathlib, mock_vcs_response, m

mock_vcs_response.dest_dir = str(mock_pathlib.parent)

with patch("vulnerabilities.importers.osv.parse_advisory_data_v2") as mock_parse:
with patch(
"vulnerabilities.pipelines.v2_importers.pypa_importer.parse_advisory_data_v3"
) as mock_parse:
# Mock parse_advisory_data to raise an error on invalid YAML
mock_parse.side_effect = saneyaml.YAMLError("Invalid YAML")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ def test_collect_advisories(mock_requests_get, mock_zip_data):
pipeline.fetch_zip()

# Mock the `parse_advisory_data_v2` function to return a dummy AdvisoryData
with patch("vulnerabilities.importers.osv.parse_advisory_data_v2") as mock_parse:
with patch(
"vulnerabilities.pipelines.v2_importers.pysec_importer.parse_advisory_data_v3"
) as mock_parse:
mock_parse.return_value = AdvisoryData(
advisory_id="PYSEC-1234",
summary="Sample PyPI advisory",
Expand Down Expand Up @@ -117,7 +119,9 @@ def test_collect_advisories_invalid_file(mock_requests_get, mock_zip_data):
pipeline.fetch_zip()

# Mock the `parse_advisory_data_v2` function
with patch("vulnerabilities.importers.osv.parse_advisory_data_v2") as mock_parse:
with patch(
"vulnerabilities.pipelines.v2_importers.pysec_importer.parse_advisory_data_v3"
) as mock_parse:
mock_parse.return_value = AdvisoryData(
advisory_id="PYSEC-1234",
summary="Sample PyPI advisory",
Expand Down
84 changes: 84 additions & 0 deletions vulnerabilities/tests/test_data/osv_test/github/github-1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"schema_version": "1.4.0",
"id": "GHSA-2hjr-vmf3-xwvp",
"modified": "2024-07-26T14:18:08Z",
"published": "2024-07-26T06:30:47Z",
"aliases": [
"CVE-2023-49921"
],
"summary": "Elasticsearch Insertion of Sensitive Information into Log File",
"details": "An issue was discovered by Elastic whereby Watcher search input logged the search query results on DEBUG log level. This could lead to raw contents of documents stored in Elasticsearch to be printed in logs. Elastic has released 8.11.2 and 7.17.16 that resolves this issue by removing this excessive logging. This issue only affects users that use Watcher and have a Watch defined that uses the search input and additionally have set the search input’s logger to DEBUG or finer, for example using: org.elasticsearch.xpack.watcher.input.search, org.elasticsearch.xpack.watcher.input, org.elasticsearch.xpack.watcher, or wider, since the loggers are hierarchical.",
"severity": [
{
"type": "CVSS_V3",
"score": "CVSS:3.1/AV:A/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N"
},
{
"type": "CVSS_V4",
"score": "CVSS:4.0/AV:A/AC:L/AT:P/PR:L/UI:P/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N"
}
],
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "org.elasticsearch:elasticsearch"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"fixed": "7.17.16"
}
]
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "org.elasticsearch:elasticsearch"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "8.0.0"
},
{
"fixed": "8.11.2"
}
]
}
]
}
],
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-49921"
},
{
"type": "WEB",
"url": "https://discuss.elastic.co/t/elasticsearch-8-11-2-7-17-16-security-update-esa-2023-29/349179"
},
{
"type": "PACKAGE",
"url": "https://github.com/elastic/elasticsearch"
}
],
"database_specific": {
"cwe_ids": [
"CWE-532"
],
"severity": "MODERATE",
"github_reviewed": true,
"github_reviewed_at": "2024-07-26T14:18:08Z",
"nvd_published_at": "2024-07-26T05:15:10Z"
}
}
64 changes: 64 additions & 0 deletions vulnerabilities/tests/test_data/osv_test/github/github-2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"schema_version": "1.4.0",
"id": "GHSA-2jm2-2p35-rp3j",
"modified": "2025-11-19T21:55:33Z",
"published": "2025-11-19T21:00:37Z",
"aliases": [
"CVE-2025-65103"
],
"summary": "OpenSTAManager has Authenticated SQL Injection in API via 'display' parameter",
"details": "### Summary\nAn authenticated SQL Injection vulnerability in the API allows any user, regardless of permission level, to execute arbitrary SQL queries. By manipulating the `display` parameter in an API request, an attacker can exfiltrate, modify, or delete any data in the database, leading to a full system compromise.\n\n### Details\nThe vulnerability is located in the `retrieve()` method within `src/API/Manager.php`.\n\nUser input from the `display` GET parameter is processed without proper validation. The code strips the surrounding brackets `[]`, splits the string by commas, and then passes each resulting element directly into the `selectRaw()` function of the query builder.\n\n```php\n// User input from 'display' is taken without sanitization.\n$select = !empty($request['display']) ? explode(',', substr((string) $request['display'], 1, -1)) : null;\n\n// ...\n\n// The unsanitized input is passed directly to `selectRaw()`.\nforeach ($select as $s) {\n $query->selectRaw($s);\n}\n```\n\nSince `selectRaw()` is designed to execute raw SQL expressions, it executes any malicious SQL code provided in the `display` parameter.\n\n### PoC\n1. Log in to an OpenSTAManager instance as any user.\n2. Navigate to the user's profile page to obtain their personal API Token.\n3. Use this API token to send a specially crafted GET request to the API endpoint.\n\n**Time-Based Blind Injection Test:**\n\nReplace `<your_host>`, `<your_token>`, and `<resource_name>` with your actual values. `anagrafiche` is a valid resource.\n\n```bash\ncurl \"http://<your_host>/openstamanager/api?token=<your_token>&resource=anagrafiche&display=[1,SLEEP(5)]\"\n```\n\nThe server will delay its response by approximately 5 seconds, confirming the `SLEEP(5)` command was executed by the database.\n\n### Impact\nThis is a critical SQL Injection vulnerability. Any authenticated user, even those with the lowest privileges, can exploit this vulnerability to:\n\n* **Exfiltrate all data** from the database (e.g., user credentials, customer information, invoices, internal data).\n* **Modify or delete data**, compromising data integrity.\n* Potentially achieve further system compromise, depending on the database user's privileges and system configuration.",
"severity": [
{
"type": "CVSS_V3",
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"
}
],
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "devcode-it/openstamanager"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"fixed": "2.9.5"
}
]
}
],
"database_specific": {
"last_known_affected_version_range": "<= 2.9.4"
}
}
],
"references": [
{
"type": "WEB",
"url": "https://github.com/devcode-it/openstamanager/security/advisories/GHSA-2jm2-2p35-rp3j"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-65103"
},
{
"type": "PACKAGE",
"url": "https://github.com/devcode-it/openstamanager"
}
],
"database_specific": {
"cwe_ids": [
"CWE-89"
],
"severity": "HIGH",
"github_reviewed": true,
"github_reviewed_at": "2025-11-19T21:00:37Z",
"nvd_published_at": "2025-11-19T20:15:54Z"
}
}
Loading
Loading