Rename Concelier Source modules to Connector
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
{
|
||||
"advisoryKey": "OSV-2025-4242",
|
||||
"affectedPackages": [
|
||||
{
|
||||
"type": "semver",
|
||||
"identifier": "npm:conflict/package",
|
||||
"platform": "npm",
|
||||
"versionRanges": [
|
||||
{
|
||||
"fixedVersion": "1.5.0",
|
||||
"introducedVersion": "1.0.0",
|
||||
"lastAffectedVersion": "1.4.2",
|
||||
"primitives": {
|
||||
"evr": null,
|
||||
"hasVendorExtensions": false,
|
||||
"nevra": null,
|
||||
"semVer": {
|
||||
"constraintExpression": null,
|
||||
"exactValue": null,
|
||||
"fixed": "1.5.0",
|
||||
"fixedInclusive": false,
|
||||
"introduced": "1.0.0",
|
||||
"introducedInclusive": true,
|
||||
"lastAffected": "1.4.2",
|
||||
"lastAffectedInclusive": true,
|
||||
"style": "range"
|
||||
},
|
||||
"vendorExtensions": null
|
||||
},
|
||||
"provenance": {
|
||||
"source": "osv",
|
||||
"kind": "range",
|
||||
"value": "npm:conflict/package",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-03-06T12:05:00+00:00",
|
||||
"fieldMask": [
|
||||
"affectedpackages[].versionranges[]"
|
||||
]
|
||||
},
|
||||
"rangeExpression": null,
|
||||
"rangeKind": "semver"
|
||||
}
|
||||
],
|
||||
"normalizedVersions": [
|
||||
{
|
||||
"scheme": "semver",
|
||||
"type": "range",
|
||||
"min": "1.0.0",
|
||||
"minInclusive": true,
|
||||
"max": "1.5.0",
|
||||
"maxInclusive": false,
|
||||
"value": null,
|
||||
"notes": "osv:npm:OSV-2025-4242:npm:conflict/package"
|
||||
}
|
||||
],
|
||||
"statuses": [],
|
||||
"provenance": [
|
||||
{
|
||||
"source": "osv",
|
||||
"kind": "affected",
|
||||
"value": "npm:conflict/package",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-03-06T12:05:00+00:00",
|
||||
"fieldMask": [
|
||||
"affectedpackages[]"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"CVE-2025-4242",
|
||||
"GHSA-qqqq-wwww-eeee",
|
||||
"OSV-2025-4242"
|
||||
],
|
||||
"canonicalMetricId": "3.1|CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:L/I:L/A:L",
|
||||
"credits": [
|
||||
{
|
||||
"displayName": "osv-reporter",
|
||||
"role": "reporter",
|
||||
"contacts": [
|
||||
"mailto:osv-reporter@example.com"
|
||||
],
|
||||
"provenance": {
|
||||
"source": "osv",
|
||||
"kind": "credit",
|
||||
"value": "osv-reporter",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-03-06T12:05:00+00:00",
|
||||
"fieldMask": [
|
||||
"credits[]"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"cvssMetrics": [
|
||||
{
|
||||
"baseScore": 4.6,
|
||||
"baseSeverity": "medium",
|
||||
"provenance": {
|
||||
"source": "osv",
|
||||
"kind": "cvss",
|
||||
"value": "CVSS_V3",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-03-06T12:05:00+00:00",
|
||||
"fieldMask": []
|
||||
},
|
||||
"vector": "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:L/I:L/A:L",
|
||||
"version": "3.1"
|
||||
}
|
||||
],
|
||||
"cwes": [],
|
||||
"description": "OSV captures the latest container escape details including patched version metadata.",
|
||||
"exploitKnown": false,
|
||||
"language": "en",
|
||||
"modified": "2025-03-06T12:00:00+00:00",
|
||||
"provenance": [
|
||||
{
|
||||
"source": "osv",
|
||||
"kind": "document",
|
||||
"value": "https://api.osv.dev/v1/vulns/OSV-2025-4242",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-03-06T11:30:00+00:00",
|
||||
"fieldMask": [
|
||||
"advisory"
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "osv",
|
||||
"kind": "mapping",
|
||||
"value": "OSV-2025-4242",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-03-06T12:05:00+00:00",
|
||||
"fieldMask": [
|
||||
"advisory"
|
||||
]
|
||||
}
|
||||
],
|
||||
"published": "2025-02-28T00:00:00+00:00",
|
||||
"references": [
|
||||
{
|
||||
"kind": "patch",
|
||||
"provenance": {
|
||||
"source": "osv",
|
||||
"kind": "reference",
|
||||
"value": "https://github.com/conflict/package/commit/abcdef1234567890",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-03-06T12:05:00+00:00",
|
||||
"fieldMask": [
|
||||
"references[]"
|
||||
]
|
||||
},
|
||||
"sourceTag": "FIX",
|
||||
"summary": null,
|
||||
"url": "https://github.com/conflict/package/commit/abcdef1234567890"
|
||||
},
|
||||
{
|
||||
"kind": "advisory",
|
||||
"provenance": {
|
||||
"source": "osv",
|
||||
"kind": "reference",
|
||||
"value": "https://osv.dev/vulnerability/OSV-2025-4242",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-03-06T12:05:00+00:00",
|
||||
"fieldMask": [
|
||||
"references[]"
|
||||
]
|
||||
},
|
||||
"sourceTag": "ADVISORY",
|
||||
"summary": null,
|
||||
"url": "https://osv.dev/vulnerability/OSV-2025-4242"
|
||||
}
|
||||
],
|
||||
"severity": "medium",
|
||||
"summary": "OSV captures the latest container escape details including patched version metadata.",
|
||||
"title": "Container escape for conflict-package"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,519 @@
|
||||
[
|
||||
{
|
||||
"ghsa_id": "GHSA-wv4w-6qv2-qqfg",
|
||||
"cve_id": "CVE-2025-61783",
|
||||
"url": "https://api.github.com/advisories/GHSA-wv4w-6qv2-qqfg",
|
||||
"html_url": "https://github.com/advisories/GHSA-wv4w-6qv2-qqfg",
|
||||
"summary": "Python Social Auth - Django has unsafe account association ",
|
||||
"description": "### Impact\n\nUpon authentication, the user could be associated by e-mail even if the \u0060associate_by_email\u0060 pipeline was not included. This could lead to account compromise when a third-party authentication service does not validate provided e-mail addresses or doesn\u0027t require unique e-mail addresses.\n\n### Patches\n\n* https://github.com/python-social-auth/social-app-django/pull/803\n\n### Workarounds\n\nReview the authentication service policy on e-mail addresses; many will not allow exploiting this vulnerability.",
|
||||
"type": "reviewed",
|
||||
"severity": "medium",
|
||||
"repository_advisory_url": "https://api.github.com/repos/python-social-auth/social-app-django/security-advisories/GHSA-wv4w-6qv2-qqfg",
|
||||
"source_code_location": "https://github.com/python-social-auth/social-app-django",
|
||||
"identifiers": [
|
||||
{
|
||||
"value": "GHSA-wv4w-6qv2-qqfg",
|
||||
"type": "GHSA"
|
||||
},
|
||||
{
|
||||
"value": "CVE-2025-61783",
|
||||
"type": "CVE"
|
||||
}
|
||||
],
|
||||
"references": [
|
||||
"https://github.com/python-social-auth/social-app-django/security/advisories/GHSA-wv4w-6qv2-qqfg",
|
||||
"https://github.com/python-social-auth/social-app-django/issues/220",
|
||||
"https://github.com/python-social-auth/social-app-django/issues/231",
|
||||
"https://github.com/python-social-auth/social-app-django/issues/634",
|
||||
"https://github.com/python-social-auth/social-app-django/pull/803",
|
||||
"https://github.com/python-social-auth/social-app-django/commit/10c80e2ebabeccd4e9c84ad0e16e1db74148ed4c",
|
||||
"https://github.com/advisories/GHSA-wv4w-6qv2-qqfg"
|
||||
],
|
||||
"published_at": "2025-10-09T17:08:05Z",
|
||||
"updated_at": "2025-10-09T17:08:06Z",
|
||||
"github_reviewed_at": "2025-10-09T17:08:05Z",
|
||||
"nvd_published_at": null,
|
||||
"withdrawn_at": null,
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"package": {
|
||||
"ecosystem": "pip",
|
||||
"name": "social-auth-app-django"
|
||||
},
|
||||
"vulnerable_version_range": "\u003C 5.6.0",
|
||||
"first_patched_version": "5.6.0",
|
||||
"vulnerable_functions": []
|
||||
}
|
||||
],
|
||||
"cvss_severities": {
|
||||
"cvss_v3": {
|
||||
"vector_string": null,
|
||||
"score": 0.0
|
||||
},
|
||||
"cvss_v4": {
|
||||
"vector_string": "CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N",
|
||||
"score": 6.3
|
||||
}
|
||||
},
|
||||
"cwes": [
|
||||
{
|
||||
"cwe_id": "CWE-290",
|
||||
"name": "Authentication Bypass by Spoofing"
|
||||
}
|
||||
],
|
||||
"credits": [
|
||||
{
|
||||
"user": {
|
||||
"login": "mel-mason",
|
||||
"id": 19391457,
|
||||
"node_id": "MDQ6VXNlcjE5MzkxNDU3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19391457?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/mel-mason",
|
||||
"html_url": "https://github.com/mel-mason",
|
||||
"followers_url": "https://api.github.com/users/mel-mason/followers",
|
||||
"following_url": "https://api.github.com/users/mel-mason/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/mel-mason/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/mel-mason/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/mel-mason/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/mel-mason/orgs",
|
||||
"repos_url": "https://api.github.com/users/mel-mason/repos",
|
||||
"events_url": "https://api.github.com/users/mel-mason/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/mel-mason/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"type": "reporter"
|
||||
},
|
||||
{
|
||||
"user": {
|
||||
"login": "vanya909",
|
||||
"id": 53380238,
|
||||
"node_id": "MDQ6VXNlcjUzMzgwMjM4",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/53380238?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/vanya909",
|
||||
"html_url": "https://github.com/vanya909",
|
||||
"followers_url": "https://api.github.com/users/vanya909/followers",
|
||||
"following_url": "https://api.github.com/users/vanya909/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/vanya909/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/vanya909/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/vanya909/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/vanya909/orgs",
|
||||
"repos_url": "https://api.github.com/users/vanya909/repos",
|
||||
"events_url": "https://api.github.com/users/vanya909/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/vanya909/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"type": "reporter"
|
||||
},
|
||||
{
|
||||
"user": {
|
||||
"login": "nijel",
|
||||
"id": 212189,
|
||||
"node_id": "MDQ6VXNlcjIxMjE4OQ==",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/212189?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/nijel",
|
||||
"html_url": "https://github.com/nijel",
|
||||
"followers_url": "https://api.github.com/users/nijel/followers",
|
||||
"following_url": "https://api.github.com/users/nijel/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/nijel/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/nijel/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/nijel/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/nijel/orgs",
|
||||
"repos_url": "https://api.github.com/users/nijel/repos",
|
||||
"events_url": "https://api.github.com/users/nijel/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/nijel/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"type": "remediation_developer"
|
||||
}
|
||||
],
|
||||
"cvss": {
|
||||
"vector_string": null,
|
||||
"score": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"ghsa_id": "GHSA-cjjf-27cc-pvmv",
|
||||
"cve_id": "CVE-2025-61773",
|
||||
"url": "https://api.github.com/advisories/GHSA-cjjf-27cc-pvmv",
|
||||
"html_url": "https://github.com/advisories/GHSA-cjjf-27cc-pvmv",
|
||||
"summary": "pyLoad CNL and captcha handlers allow Code Injection via unsanitized parameters",
|
||||
"description": "### Summary\npyLoad web interface contained insufficient input validation in both the Captcha script endpoint and the Click\u0027N\u0027Load (CNL) Blueprint. This flaw allowed untrusted user input to be processed unsafely, which could be exploited by an attacker to inject arbitrary content into the web UI or manipulate request handling. The vulnerability could lead to client-side code execution (XSS) or other unintended behaviors when a malicious payload is submitted.\n\nuser-supplied parameters from HTTP requests were not adequately validated or sanitized before being passed into the application logic and response generation. This allowed crafted input to alter the expected execution flow.\n CNL (Click\u0027N\u0027Load) blueprint exposed unsafe handling of untrusted parameters in HTTP requests. The application did not consistently enforce input validation or encoding, making it possible for an attacker to craft malicious requests.\n\n### PoC\n\n1. Run a vulnerable version of pyLoad prior to commit [\u0060f9d27f2\u0060](https://github.com/pyload/pyload/pull/4624).\n2. Start the web UI and access the Captcha or CNL endpoints.\n3. Submit a crafted request containing malicious JavaScript payloads in unvalidated parameters (\u0060/flash/addcrypted2?jk=function(){alert(1)}\u0026crypted=12345\u0060).\n4. Observe that the payload is reflected and executed in the client\u2019s browser, demonstrating cross-site scripting (XSS).\n\nExample request:\n\n\u0060\u0060\u0060http\nGET /flash/addcrypted2?jk=function(){alert(1)}\u0026crypted=12345 HTTP/1.1\nHost: 127.0.0.1:8000\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 107\n\u0060\u0060\u0060\n\n### Impact\n\nExploiting this vulnerability allows an attacker to inject and execute arbitrary JavaScript within the browser session of a user accessing the pyLoad Web UI. In practice, this means an attacker could impersonate an administrator, steal authentication cookies or tokens, and perform unauthorized actions on behalf of the victim. Because the affected endpoints are part of the core interface, a successful attack undermines the trust and security of the entire application, potentially leading to a full compromise of the management interface and the data it controls. The impact is particularly severe in cases where the Web UI is exposed over a network without additional access restrictions, as it enables remote attackers to directly target users with crafted links or requests that trigger the vulnerability.",
|
||||
"type": "reviewed",
|
||||
"severity": "high",
|
||||
"repository_advisory_url": "https://api.github.com/repos/pyload/pyload/security-advisories/GHSA-cjjf-27cc-pvmv",
|
||||
"source_code_location": "https://github.com/pyload/pyload",
|
||||
"identifiers": [
|
||||
{
|
||||
"value": "GHSA-cjjf-27cc-pvmv",
|
||||
"type": "GHSA"
|
||||
},
|
||||
{
|
||||
"value": "CVE-2025-61773",
|
||||
"type": "CVE"
|
||||
}
|
||||
],
|
||||
"references": [
|
||||
"https://github.com/pyload/pyload/security/advisories/GHSA-cjjf-27cc-pvmv",
|
||||
"https://github.com/pyload/pyload/pull/4624",
|
||||
"https://github.com/pyload/pyload/commit/5823327d0b797161c7195a1f660266d30a69f0ca",
|
||||
"https://github.com/advisories/GHSA-cjjf-27cc-pvmv"
|
||||
],
|
||||
"published_at": "2025-10-09T15:19:48Z",
|
||||
"updated_at": "2025-10-09T15:19:48Z",
|
||||
"github_reviewed_at": "2025-10-09T15:19:48Z",
|
||||
"nvd_published_at": null,
|
||||
"withdrawn_at": null,
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"package": {
|
||||
"ecosystem": "pip",
|
||||
"name": "pyload-ng"
|
||||
},
|
||||
"vulnerable_version_range": "\u003C 0.5.0b3.dev91",
|
||||
"first_patched_version": "0.5.0b3.dev91",
|
||||
"vulnerable_functions": []
|
||||
}
|
||||
],
|
||||
"cvss_severities": {
|
||||
"cvss_v3": {
|
||||
"vector_string": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N",
|
||||
"score": 8.1
|
||||
},
|
||||
"cvss_v4": {
|
||||
"vector_string": null,
|
||||
"score": 0.0
|
||||
}
|
||||
},
|
||||
"cwes": [
|
||||
{
|
||||
"cwe_id": "CWE-74",
|
||||
"name": "Improper Neutralization of Special Elements in Output Used by a Downstream Component (\u0027Injection\u0027)"
|
||||
},
|
||||
{
|
||||
"cwe_id": "CWE-79",
|
||||
"name": "Improper Neutralization of Input During Web Page Generation (\u0027Cross-site Scripting\u0027)"
|
||||
},
|
||||
{
|
||||
"cwe_id": "CWE-94",
|
||||
"name": "Improper Control of Generation of Code (\u0027Code Injection\u0027)"
|
||||
},
|
||||
{
|
||||
"cwe_id": "CWE-116",
|
||||
"name": "Improper Encoding or Escaping of Output"
|
||||
}
|
||||
],
|
||||
"credits": [
|
||||
{
|
||||
"user": {
|
||||
"login": "odaysec",
|
||||
"id": 47859767,
|
||||
"node_id": "MDQ6VXNlcjQ3ODU5NzY3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/47859767?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/odaysec",
|
||||
"html_url": "https://github.com/odaysec",
|
||||
"followers_url": "https://api.github.com/users/odaysec/followers",
|
||||
"following_url": "https://api.github.com/users/odaysec/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/odaysec/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/odaysec/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/odaysec/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/odaysec/orgs",
|
||||
"repos_url": "https://api.github.com/users/odaysec/repos",
|
||||
"events_url": "https://api.github.com/users/odaysec/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/odaysec/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"type": "reporter"
|
||||
}
|
||||
],
|
||||
"cvss": {
|
||||
"vector_string": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N",
|
||||
"score": 8.1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ghsa_id": "GHSA-77vh-xpmg-72qh",
|
||||
"cve_id": null,
|
||||
"url": "https://api.github.com/advisories/GHSA-77vh-xpmg-72qh",
|
||||
"html_url": "https://github.com/advisories/GHSA-77vh-xpmg-72qh",
|
||||
"summary": "Clarify \u0060mediaType\u0060 handling",
|
||||
"description": "### Impact\nIn the OCI Image Specification version 1.0.1 and prior, manifest and index documents are not self-describing and documents with a single digest could be interpreted as either a manifest or an index.\n\n### Patches\nThe Image Specification will be updated to recommend that both manifest and index documents contain a \u0060mediaType\u0060 field to identify the type of document.\nRelease [v1.0.2](https://github.com/opencontainers/image-spec/releases/tag/v1.0.2) includes these updates.\n\n### Workarounds\nSoftware attempting to deserialize an ambiguous document may reject the document if it contains both \u201Cmanifests\u201D and \u201Clayers\u201D fields or \u201Cmanifests\u201D and \u201Cconfig\u201D fields.\n\n### References\nhttps://github.com/opencontainers/distribution-spec/security/advisories/GHSA-mc8v-mgrf-8f4m\n\n### For more information\nIf you have any questions or comments about this advisory:\n* Open an issue in https://github.com/opencontainers/image-spec\n* Email us at [security@opencontainers.org](mailto:security@opencontainers.org)\n* https://github.com/opencontainers/image-spec/commits/v1.0.2\n",
|
||||
"type": "reviewed",
|
||||
"severity": "low",
|
||||
"repository_advisory_url": "https://api.github.com/repos/opencontainers/image-spec/security-advisories/GHSA-77vh-xpmg-72qh",
|
||||
"source_code_location": "https://github.com/opencontainers/image-spec",
|
||||
"identifiers": [
|
||||
{
|
||||
"value": "GHSA-77vh-xpmg-72qh",
|
||||
"type": "GHSA"
|
||||
}
|
||||
],
|
||||
"references": [
|
||||
"https://github.com/opencontainers/distribution-spec/security/advisories/GHSA-mc8v-mgrf-8f4m",
|
||||
"https://github.com/opencontainers/image-spec/security/advisories/GHSA-77vh-xpmg-72qh",
|
||||
"https://github.com/opencontainers/image-spec/commit/693428a734f5bab1a84bd2f990d92ef1111cd60c",
|
||||
"https://github.com/opencontainers/image-spec/releases/tag/v1.0.2",
|
||||
"https://github.com/advisories/GHSA-77vh-xpmg-72qh"
|
||||
],
|
||||
"published_at": "2021-11-18T16:02:41Z",
|
||||
"updated_at": "2023-01-09T05:05:32Z",
|
||||
"github_reviewed_at": "2021-11-17T23:13:41Z",
|
||||
"nvd_published_at": null,
|
||||
"withdrawn_at": null,
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"package": {
|
||||
"ecosystem": "go",
|
||||
"name": "github.com/opencontainers/image-spec"
|
||||
},
|
||||
"vulnerable_version_range": "\u003C 1.0.2",
|
||||
"first_patched_version": "1.0.2",
|
||||
"vulnerable_functions": []
|
||||
}
|
||||
],
|
||||
"cvss_severities": {
|
||||
"cvss_v3": {
|
||||
"vector_string": "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:N/I:L/A:N",
|
||||
"score": 3.0
|
||||
},
|
||||
"cvss_v4": {
|
||||
"vector_string": null,
|
||||
"score": 0.0
|
||||
}
|
||||
},
|
||||
"cwes": [
|
||||
{
|
||||
"cwe_id": "CWE-843",
|
||||
"name": "Access of Resource Using Incompatible Type (\u0027Type Confusion\u0027)"
|
||||
}
|
||||
],
|
||||
"credits": [],
|
||||
"cvss": {
|
||||
"vector_string": "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:N/I:L/A:N",
|
||||
"score": 3.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"ghsa_id": "GHSA-7rjr-3q55-vv33",
|
||||
"cve_id": "CVE-2021-45046",
|
||||
"url": "https://api.github.com/advisories/GHSA-7rjr-3q55-vv33",
|
||||
"html_url": "https://github.com/advisories/GHSA-7rjr-3q55-vv33",
|
||||
"summary": "Incomplete fix for Apache Log4j vulnerability",
|
||||
"description": "# Impact\n\nThe fix to address [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) in Apache Log4j 2.15.0 was incomplete in certain non-default configurations. This could allow attackers with control over Thread Context Map (MDC) input data when the logging configuration uses a non-default Pattern Layout with either a Context Lookup (for example, $${ctx:loginId}) or a Thread Context Map pattern (%X, %mdc, or %MDC) to craft malicious input data using a JNDI Lookup pattern resulting in a remote code execution (RCE) attack. \n\n## Affected packages\nOnly the \u0060org.apache.logging.log4j:log4j-core\u0060 package is directly affected by this vulnerability. The \u0060org.apache.logging.log4j:log4j-api\u0060 should be kept at the same version as the \u0060org.apache.logging.log4j:log4j-core\u0060 package to ensure compatability if in use.\n\n# Mitigation\n\nLog4j 2.16.0 fixes this issue by removing support for message lookup patterns and disabling JNDI functionality by default. This issue can be mitigated in prior releases (\u003C 2.16.0) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class).\n\nLog4j 2.15.0 restricts JNDI LDAP lookups to localhost by default. Note that previous mitigations involving configuration such as to set the system property \u0060log4j2.formatMsgNoLookups\u0060 to \u0060true\u0060 do NOT mitigate this specific vulnerability.",
|
||||
"type": "reviewed",
|
||||
"severity": "critical",
|
||||
"repository_advisory_url": null,
|
||||
"source_code_location": "",
|
||||
"identifiers": [
|
||||
{
|
||||
"value": "GHSA-7rjr-3q55-vv33",
|
||||
"type": "GHSA"
|
||||
},
|
||||
{
|
||||
"value": "CVE-2021-45046",
|
||||
"type": "CVE"
|
||||
}
|
||||
],
|
||||
"references": [
|
||||
"https://nvd.nist.gov/vuln/detail/CVE-2021-45046",
|
||||
"https://github.com/advisories/GHSA-jfh8-c2jp-5v3q",
|
||||
"https://logging.apache.org/log4j/2.x/security.html",
|
||||
"https://www.openwall.com/lists/oss-security/2021/12/14/4",
|
||||
"https://www.cve.org/CVERecord?id=CVE-2021-44228",
|
||||
"http://www.openwall.com/lists/oss-security/2021/12/14/4",
|
||||
"https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00646.html",
|
||||
"http://www.openwall.com/lists/oss-security/2021/12/15/3",
|
||||
"https://cert-portal.siemens.com/productcert/pdf/ssa-661247.pdf",
|
||||
"https://cert-portal.siemens.com/productcert/pdf/ssa-714170.pdf",
|
||||
"https://www.kb.cert.org/vuls/id/930724",
|
||||
"https://www.debian.org/security/2021/dsa-5022",
|
||||
"https://psirt.global.sonicwall.com/vuln-detail/SNWLID-2021-0032",
|
||||
"https://www.oracle.com/security-alerts/alert-cve-2021-44228.html",
|
||||
"http://www.openwall.com/lists/oss-security/2021/12/18/1",
|
||||
"https://cert-portal.siemens.com/productcert/pdf/ssa-397453.pdf",
|
||||
"https://cert-portal.siemens.com/productcert/pdf/ssa-479842.pdf",
|
||||
"https://www.oracle.com/security-alerts/cpujan2022.html",
|
||||
"https://www.oracle.com/security-alerts/cpuapr2022.html",
|
||||
"https://www.oracle.com/security-alerts/cpujul2022.html",
|
||||
"https://security.gentoo.org/glsa/202310-16",
|
||||
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/SIG7FZULMNK2XF6FZRU4VWYDQXNMUGAJ",
|
||||
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/EOKPQGV24RRBBI4TBZUDQMM4MEH7MXCY",
|
||||
"https://sec.cloudapps.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-apache-log4j-qRuKNEbd",
|
||||
"https://github.com/advisories/GHSA-7rjr-3q55-vv33"
|
||||
],
|
||||
"published_at": "2021-12-14T18:01:28Z",
|
||||
"updated_at": "2025-05-09T12:28:41Z",
|
||||
"github_reviewed_at": "2021-12-14T17:55:00Z",
|
||||
"nvd_published_at": "2021-12-14T19:15:00Z",
|
||||
"withdrawn_at": null,
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"package": {
|
||||
"ecosystem": "maven",
|
||||
"name": "org.apache.logging.log4j:log4j-core"
|
||||
},
|
||||
"vulnerable_version_range": "\u003E= 2.13.0, \u003C 2.16.0",
|
||||
"first_patched_version": "2.16.0",
|
||||
"vulnerable_functions": []
|
||||
},
|
||||
{
|
||||
"package": {
|
||||
"ecosystem": "maven",
|
||||
"name": "org.apache.logging.log4j:log4j-core"
|
||||
},
|
||||
"vulnerable_version_range": "\u003C 2.12.2",
|
||||
"first_patched_version": "2.12.2",
|
||||
"vulnerable_functions": []
|
||||
},
|
||||
{
|
||||
"package": {
|
||||
"ecosystem": "maven",
|
||||
"name": "org.ops4j.pax.logging:pax-logging-log4j2"
|
||||
},
|
||||
"vulnerable_version_range": "\u003E= 1.8.0, \u003C 1.9.2",
|
||||
"first_patched_version": "1.9.2",
|
||||
"vulnerable_functions": []
|
||||
},
|
||||
{
|
||||
"package": {
|
||||
"ecosystem": "maven",
|
||||
"name": "org.ops4j.pax.logging:pax-logging-log4j2"
|
||||
},
|
||||
"vulnerable_version_range": "\u003E= 1.10.0, \u003C 1.10.8",
|
||||
"first_patched_version": "1.10.8",
|
||||
"vulnerable_functions": []
|
||||
},
|
||||
{
|
||||
"package": {
|
||||
"ecosystem": "maven",
|
||||
"name": "org.ops4j.pax.logging:pax-logging-log4j2"
|
||||
},
|
||||
"vulnerable_version_range": "\u003E= 1.11.0, \u003C 1.11.11",
|
||||
"first_patched_version": "1.11.11",
|
||||
"vulnerable_functions": []
|
||||
},
|
||||
{
|
||||
"package": {
|
||||
"ecosystem": "maven",
|
||||
"name": "org.ops4j.pax.logging:pax-logging-log4j2"
|
||||
},
|
||||
"vulnerable_version_range": "\u003E= 2.0.0, \u003C 2.0.12",
|
||||
"first_patched_version": "2.0.12",
|
||||
"vulnerable_functions": []
|
||||
}
|
||||
],
|
||||
"cvss_severities": {
|
||||
"cvss_v3": {
|
||||
"vector_string": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H",
|
||||
"score": 9.1
|
||||
},
|
||||
"cvss_v4": {
|
||||
"vector_string": null,
|
||||
"score": 0.0
|
||||
}
|
||||
},
|
||||
"cwes": [
|
||||
{
|
||||
"cwe_id": "CWE-502",
|
||||
"name": "Deserialization of Untrusted Data"
|
||||
},
|
||||
{
|
||||
"cwe_id": "CWE-917",
|
||||
"name": "Improper Neutralization of Special Elements used in an Expression Language Statement (\u0027Expression Language Injection\u0027)"
|
||||
}
|
||||
],
|
||||
"credits": [
|
||||
{
|
||||
"user": {
|
||||
"login": "mrjonstrong",
|
||||
"id": 42520909,
|
||||
"node_id": "MDQ6VXNlcjQyNTIwOTA5",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/42520909?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/mrjonstrong",
|
||||
"html_url": "https://github.com/mrjonstrong",
|
||||
"followers_url": "https://api.github.com/users/mrjonstrong/followers",
|
||||
"following_url": "https://api.github.com/users/mrjonstrong/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/mrjonstrong/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/mrjonstrong/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/mrjonstrong/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/mrjonstrong/orgs",
|
||||
"repos_url": "https://api.github.com/users/mrjonstrong/repos",
|
||||
"events_url": "https://api.github.com/users/mrjonstrong/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/mrjonstrong/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"type": "analyst"
|
||||
},
|
||||
{
|
||||
"user": {
|
||||
"login": "afdesk",
|
||||
"id": 19297627,
|
||||
"node_id": "MDQ6VXNlcjE5Mjk3NjI3",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19297627?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/afdesk",
|
||||
"html_url": "https://github.com/afdesk",
|
||||
"followers_url": "https://api.github.com/users/afdesk/followers",
|
||||
"following_url": "https://api.github.com/users/afdesk/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/afdesk/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/afdesk/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/afdesk/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/afdesk/orgs",
|
||||
"repos_url": "https://api.github.com/users/afdesk/repos",
|
||||
"events_url": "https://api.github.com/users/afdesk/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/afdesk/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"type": "analyst"
|
||||
},
|
||||
{
|
||||
"user": {
|
||||
"login": "ppkarwasz",
|
||||
"id": 12533274,
|
||||
"node_id": "MDQ6VXNlcjEyNTMzMjc0",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/12533274?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/ppkarwasz",
|
||||
"html_url": "https://github.com/ppkarwasz",
|
||||
"followers_url": "https://api.github.com/users/ppkarwasz/followers",
|
||||
"following_url": "https://api.github.com/users/ppkarwasz/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/ppkarwasz/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/ppkarwasz/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/ppkarwasz/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/ppkarwasz/orgs",
|
||||
"repos_url": "https://api.github.com/users/ppkarwasz/repos",
|
||||
"events_url": "https://api.github.com/users/ppkarwasz/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/ppkarwasz/received_events",
|
||||
"type": "User",
|
||||
"user_view_type": "public",
|
||||
"site_admin": false
|
||||
},
|
||||
"type": "analyst"
|
||||
}
|
||||
],
|
||||
"cvss": {
|
||||
"vector_string": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H",
|
||||
"score": 9.1
|
||||
},
|
||||
"epss": {
|
||||
"percentage": 0.9434,
|
||||
"percentile": 0.9995
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,714 @@
|
||||
[
|
||||
{
|
||||
"id": "GHSA-wv4w-6qv2-qqfg",
|
||||
"summary": "Python Social Auth - Django has unsafe account association ",
|
||||
"details": "### Impact\n\nUpon authentication, the user could be associated by e-mail even if the \u0060associate_by_email\u0060 pipeline was not included. This could lead to account compromise when a third-party authentication service does not validate provided e-mail addresses or doesn\u0027t require unique e-mail addresses.\n\n### Patches\n\n* https://github.com/python-social-auth/social-app-django/pull/803\n\n### Workarounds\n\nReview the authentication service policy on e-mail addresses; many will not allow exploiting this vulnerability.",
|
||||
"aliases": [
|
||||
"CVE-2025-61783"
|
||||
],
|
||||
"modified": "2025-10-09T17:57:29.916841Z",
|
||||
"published": "2025-10-09T17:08:05Z",
|
||||
"database_specific": {
|
||||
"github_reviewed_at": "2025-10-09T17:08:05Z",
|
||||
"severity": "MODERATE",
|
||||
"cwe_ids": [
|
||||
"CWE-290"
|
||||
],
|
||||
"github_reviewed": true,
|
||||
"nvd_published_at": null
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://github.com/python-social-auth/social-app-django/security/advisories/GHSA-wv4w-6qv2-qqfg"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://github.com/python-social-auth/social-app-django/issues/220"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://github.com/python-social-auth/social-app-django/issues/231"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://github.com/python-social-auth/social-app-django/issues/634"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://github.com/python-social-auth/social-app-django/pull/803"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://github.com/python-social-auth/social-app-django/commit/10c80e2ebabeccd4e9c84ad0e16e1db74148ed4c"
|
||||
},
|
||||
{
|
||||
"type": "PACKAGE",
|
||||
"url": "https://github.com/python-social-auth/social-app-django"
|
||||
}
|
||||
],
|
||||
"affected": [
|
||||
{
|
||||
"package": {
|
||||
"name": "social-auth-app-django",
|
||||
"ecosystem": "PyPI",
|
||||
"purl": "pkg:pypi/social-auth-app-django"
|
||||
},
|
||||
"ranges": [
|
||||
{
|
||||
"type": "ECOSYSTEM",
|
||||
"events": [
|
||||
{
|
||||
"introduced": "0"
|
||||
},
|
||||
{
|
||||
"fixed": "5.6.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
"0.0.1",
|
||||
"0.1.0",
|
||||
"1.0.0",
|
||||
"1.0.1",
|
||||
"1.1.0",
|
||||
"1.2.0",
|
||||
"2.0.0",
|
||||
"2.1.0",
|
||||
"3.0.0",
|
||||
"3.1.0",
|
||||
"3.3.0",
|
||||
"3.4.0",
|
||||
"4.0.0",
|
||||
"5.0.0",
|
||||
"5.1.0",
|
||||
"5.2.0",
|
||||
"5.3.0",
|
||||
"5.4.0",
|
||||
"5.4.1",
|
||||
"5.4.2",
|
||||
"5.4.3",
|
||||
"5.5.0",
|
||||
"5.5.1"
|
||||
],
|
||||
"database_specific": {
|
||||
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2025/10/GHSA-wv4w-6qv2-qqfg/GHSA-wv4w-6qv2-qqfg.json"
|
||||
}
|
||||
}
|
||||
],
|
||||
"schema_version": "1.7.3",
|
||||
"severity": [
|
||||
{
|
||||
"type": "CVSS_V4",
|
||||
"score": "CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "GHSA-cjjf-27cc-pvmv",
|
||||
"summary": "pyLoad CNL and captcha handlers allow Code Injection via unsanitized parameters",
|
||||
"details": "### Summary\npyLoad web interface contained insufficient input validation in both the Captcha script endpoint and the Click\u0027N\u0027Load (CNL) Blueprint. This flaw allowed untrusted user input to be processed unsafely, which could be exploited by an attacker to inject arbitrary content into the web UI or manipulate request handling. The vulnerability could lead to client-side code execution (XSS) or other unintended behaviors when a malicious payload is submitted.\n\nuser-supplied parameters from HTTP requests were not adequately validated or sanitized before being passed into the application logic and response generation. This allowed crafted input to alter the expected execution flow.\n CNL (Click\u0027N\u0027Load) blueprint exposed unsafe handling of untrusted parameters in HTTP requests. The application did not consistently enforce input validation or encoding, making it possible for an attacker to craft malicious requests.\n\n### PoC\n\n1. Run a vulnerable version of pyLoad prior to commit [\u0060f9d27f2\u0060](https://github.com/pyload/pyload/pull/4624).\n2. Start the web UI and access the Captcha or CNL endpoints.\n3. Submit a crafted request containing malicious JavaScript payloads in unvalidated parameters (\u0060/flash/addcrypted2?jk=function(){alert(1)}\u0026crypted=12345\u0060).\n4. Observe that the payload is reflected and executed in the client\u2019s browser, demonstrating cross-site scripting (XSS).\n\nExample request:\n\n\u0060\u0060\u0060http\nGET /flash/addcrypted2?jk=function(){alert(1)}\u0026crypted=12345 HTTP/1.1\nHost: 127.0.0.1:8000\nContent-Type: application/x-www-form-urlencoded\nContent-Length: 107\n\u0060\u0060\u0060\n\n### Impact\n\nExploiting this vulnerability allows an attacker to inject and execute arbitrary JavaScript within the browser session of a user accessing the pyLoad Web UI. In practice, this means an attacker could impersonate an administrator, steal authentication cookies or tokens, and perform unauthorized actions on behalf of the victim. Because the affected endpoints are part of the core interface, a successful attack undermines the trust and security of the entire application, potentially leading to a full compromise of the management interface and the data it controls. The impact is particularly severe in cases where the Web UI is exposed over a network without additional access restrictions, as it enables remote attackers to directly target users with crafted links or requests that trigger the vulnerability.",
|
||||
"aliases": [
|
||||
"CVE-2025-61773"
|
||||
],
|
||||
"modified": "2025-10-09T15:59:13.250015Z",
|
||||
"published": "2025-10-09T15:19:48Z",
|
||||
"database_specific": {
|
||||
"github_reviewed_at": "2025-10-09T15:19:48Z",
|
||||
"github_reviewed": true,
|
||||
"cwe_ids": [
|
||||
"CWE-116",
|
||||
"CWE-74",
|
||||
"CWE-79",
|
||||
"CWE-94"
|
||||
],
|
||||
"severity": "HIGH",
|
||||
"nvd_published_at": null
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://github.com/pyload/pyload/security/advisories/GHSA-cjjf-27cc-pvmv"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://github.com/pyload/pyload/pull/4624"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://github.com/pyload/pyload/commit/5823327d0b797161c7195a1f660266d30a69f0ca"
|
||||
},
|
||||
{
|
||||
"type": "PACKAGE",
|
||||
"url": "https://github.com/pyload/pyload"
|
||||
}
|
||||
],
|
||||
"affected": [
|
||||
{
|
||||
"package": {
|
||||
"name": "pyload-ng",
|
||||
"ecosystem": "PyPI",
|
||||
"purl": "pkg:pypi/pyload-ng"
|
||||
},
|
||||
"ranges": [
|
||||
{
|
||||
"type": "ECOSYSTEM",
|
||||
"events": [
|
||||
{
|
||||
"introduced": "0"
|
||||
},
|
||||
{
|
||||
"fixed": "0.5.0b3.dev91"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
"0.5.0a5.dev528",
|
||||
"0.5.0a5.dev532",
|
||||
"0.5.0a5.dev535",
|
||||
"0.5.0a5.dev536",
|
||||
"0.5.0a5.dev537",
|
||||
"0.5.0a5.dev539",
|
||||
"0.5.0a5.dev540",
|
||||
"0.5.0a5.dev545",
|
||||
"0.5.0a5.dev562",
|
||||
"0.5.0a5.dev564",
|
||||
"0.5.0a5.dev565",
|
||||
"0.5.0a6.dev570",
|
||||
"0.5.0a6.dev578",
|
||||
"0.5.0a6.dev587",
|
||||
"0.5.0a7.dev596",
|
||||
"0.5.0a8.dev602",
|
||||
"0.5.0a9.dev615",
|
||||
"0.5.0a9.dev629",
|
||||
"0.5.0a9.dev632",
|
||||
"0.5.0a9.dev641",
|
||||
"0.5.0a9.dev643",
|
||||
"0.5.0a9.dev655",
|
||||
"0.5.0a9.dev806",
|
||||
"0.5.0b1.dev1",
|
||||
"0.5.0b1.dev2",
|
||||
"0.5.0b1.dev3",
|
||||
"0.5.0b1.dev4",
|
||||
"0.5.0b1.dev5",
|
||||
"0.5.0b2.dev10",
|
||||
"0.5.0b2.dev11",
|
||||
"0.5.0b2.dev12",
|
||||
"0.5.0b2.dev9",
|
||||
"0.5.0b3.dev13",
|
||||
"0.5.0b3.dev14",
|
||||
"0.5.0b3.dev17",
|
||||
"0.5.0b3.dev18",
|
||||
"0.5.0b3.dev19",
|
||||
"0.5.0b3.dev20",
|
||||
"0.5.0b3.dev21",
|
||||
"0.5.0b3.dev22",
|
||||
"0.5.0b3.dev24",
|
||||
"0.5.0b3.dev26",
|
||||
"0.5.0b3.dev27",
|
||||
"0.5.0b3.dev28",
|
||||
"0.5.0b3.dev29",
|
||||
"0.5.0b3.dev30",
|
||||
"0.5.0b3.dev31",
|
||||
"0.5.0b3.dev32",
|
||||
"0.5.0b3.dev33",
|
||||
"0.5.0b3.dev34",
|
||||
"0.5.0b3.dev35",
|
||||
"0.5.0b3.dev38",
|
||||
"0.5.0b3.dev39",
|
||||
"0.5.0b3.dev40",
|
||||
"0.5.0b3.dev41",
|
||||
"0.5.0b3.dev42",
|
||||
"0.5.0b3.dev43",
|
||||
"0.5.0b3.dev44",
|
||||
"0.5.0b3.dev45",
|
||||
"0.5.0b3.dev46",
|
||||
"0.5.0b3.dev47",
|
||||
"0.5.0b3.dev48",
|
||||
"0.5.0b3.dev49",
|
||||
"0.5.0b3.dev50",
|
||||
"0.5.0b3.dev51",
|
||||
"0.5.0b3.dev52",
|
||||
"0.5.0b3.dev53",
|
||||
"0.5.0b3.dev54",
|
||||
"0.5.0b3.dev57",
|
||||
"0.5.0b3.dev60",
|
||||
"0.5.0b3.dev62",
|
||||
"0.5.0b3.dev64",
|
||||
"0.5.0b3.dev65",
|
||||
"0.5.0b3.dev66",
|
||||
"0.5.0b3.dev67",
|
||||
"0.5.0b3.dev68",
|
||||
"0.5.0b3.dev69",
|
||||
"0.5.0b3.dev70",
|
||||
"0.5.0b3.dev71",
|
||||
"0.5.0b3.dev72",
|
||||
"0.5.0b3.dev73",
|
||||
"0.5.0b3.dev74",
|
||||
"0.5.0b3.dev75",
|
||||
"0.5.0b3.dev76",
|
||||
"0.5.0b3.dev77",
|
||||
"0.5.0b3.dev78",
|
||||
"0.5.0b3.dev79",
|
||||
"0.5.0b3.dev80",
|
||||
"0.5.0b3.dev81",
|
||||
"0.5.0b3.dev82",
|
||||
"0.5.0b3.dev85",
|
||||
"0.5.0b3.dev87",
|
||||
"0.5.0b3.dev88",
|
||||
"0.5.0b3.dev89",
|
||||
"0.5.0b3.dev90"
|
||||
],
|
||||
"database_specific": {
|
||||
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2025/10/GHSA-cjjf-27cc-pvmv/GHSA-cjjf-27cc-pvmv.json"
|
||||
}
|
||||
}
|
||||
],
|
||||
"schema_version": "1.7.3",
|
||||
"severity": [
|
||||
{
|
||||
"type": "CVSS_V3",
|
||||
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "GHSA-77vh-xpmg-72qh",
|
||||
"summary": "Clarify \u0060mediaType\u0060 handling",
|
||||
"details": "### Impact\nIn the OCI Image Specification version 1.0.1 and prior, manifest and index documents are not self-describing and documents with a single digest could be interpreted as either a manifest or an index.\n\n### Patches\nThe Image Specification will be updated to recommend that both manifest and index documents contain a \u0060mediaType\u0060 field to identify the type of document.\nRelease [v1.0.2](https://github.com/opencontainers/image-spec/releases/tag/v1.0.2) includes these updates.\n\n### Workarounds\nSoftware attempting to deserialize an ambiguous document may reject the document if it contains both \u201Cmanifests\u201D and \u201Clayers\u201D fields or \u201Cmanifests\u201D and \u201Cconfig\u201D fields.\n\n### References\nhttps://github.com/opencontainers/distribution-spec/security/advisories/GHSA-mc8v-mgrf-8f4m\n\n### For more information\nIf you have any questions or comments about this advisory:\n* Open an issue in https://github.com/opencontainers/image-spec\n* Email us at [security@opencontainers.org](mailto:security@opencontainers.org)\n* https://github.com/opencontainers/image-spec/commits/v1.0.2\n",
|
||||
"modified": "2021-11-24T19:43:35Z",
|
||||
"published": "2021-11-18T16:02:41Z",
|
||||
"related": [
|
||||
"CGA-j36r-723f-8c29"
|
||||
],
|
||||
"database_specific": {
|
||||
"github_reviewed": true,
|
||||
"nvd_published_at": null,
|
||||
"github_reviewed_at": "2021-11-17T23:13:41Z",
|
||||
"cwe_ids": [
|
||||
"CWE-843"
|
||||
],
|
||||
"severity": "LOW"
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://github.com/opencontainers/distribution-spec/security/advisories/GHSA-mc8v-mgrf-8f4m"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://github.com/opencontainers/image-spec/security/advisories/GHSA-77vh-xpmg-72qh"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://github.com/opencontainers/image-spec/commit/693428a734f5bab1a84bd2f990d92ef1111cd60c"
|
||||
},
|
||||
{
|
||||
"type": "PACKAGE",
|
||||
"url": "https://github.com/opencontainers/image-spec"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://github.com/opencontainers/image-spec/releases/tag/v1.0.2"
|
||||
}
|
||||
],
|
||||
"affected": [
|
||||
{
|
||||
"package": {
|
||||
"name": "github.com/opencontainers/image-spec",
|
||||
"ecosystem": "Go",
|
||||
"purl": "pkg:golang/github.com/opencontainers/image-spec"
|
||||
},
|
||||
"ranges": [
|
||||
{
|
||||
"type": "SEMVER",
|
||||
"events": [
|
||||
{
|
||||
"introduced": "0"
|
||||
},
|
||||
{
|
||||
"fixed": "1.0.2"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"database_specific": {
|
||||
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2021/11/GHSA-77vh-xpmg-72qh/GHSA-77vh-xpmg-72qh.json"
|
||||
}
|
||||
}
|
||||
],
|
||||
"schema_version": "1.7.3",
|
||||
"severity": [
|
||||
{
|
||||
"type": "CVSS_V3",
|
||||
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:N/I:L/A:N"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "GHSA-7rjr-3q55-vv33",
|
||||
"summary": "Incomplete fix for Apache Log4j vulnerability",
|
||||
"details": "# Impact\n\nThe fix to address [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) in Apache Log4j 2.15.0 was incomplete in certain non-default configurations. This could allow attackers with control over Thread Context Map (MDC) input data when the logging configuration uses a non-default Pattern Layout with either a Context Lookup (for example, $${ctx:loginId}) or a Thread Context Map pattern (%X, %mdc, or %MDC) to craft malicious input data using a JNDI Lookup pattern resulting in a remote code execution (RCE) attack. \n\n## Affected packages\nOnly the \u0060org.apache.logging.log4j:log4j-core\u0060 package is directly affected by this vulnerability. The \u0060org.apache.logging.log4j:log4j-api\u0060 should be kept at the same version as the \u0060org.apache.logging.log4j:log4j-core\u0060 package to ensure compatability if in use.\n\n# Mitigation\n\nLog4j 2.16.0 fixes this issue by removing support for message lookup patterns and disabling JNDI functionality by default. This issue can be mitigated in prior releases (\u003C 2.16.0) by removing the JndiLookup class from the classpath (example: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class).\n\nLog4j 2.15.0 restricts JNDI LDAP lookups to localhost by default. Note that previous mitigations involving configuration such as to set the system property \u0060log4j2.formatMsgNoLookups\u0060 to \u0060true\u0060 do NOT mitigate this specific vulnerability.",
|
||||
"aliases": [
|
||||
"CVE-2021-45046"
|
||||
],
|
||||
"modified": "2025-05-09T13:13:16.169374Z",
|
||||
"published": "2021-12-14T18:01:28Z",
|
||||
"database_specific": {
|
||||
"github_reviewed_at": "2021-12-14T17:55:00Z",
|
||||
"cwe_ids": [
|
||||
"CWE-502",
|
||||
"CWE-917"
|
||||
],
|
||||
"github_reviewed": true,
|
||||
"severity": "CRITICAL",
|
||||
"nvd_published_at": "2021-12-14T19:15:00Z"
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"type": "ADVISORY",
|
||||
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-45046"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://www.oracle.com/security-alerts/cpujul2022.html"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://www.oracle.com/security-alerts/cpujan2022.html"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://www.oracle.com/security-alerts/cpuapr2022.html"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://www.oracle.com/security-alerts/alert-cve-2021-44228.html"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://www.openwall.com/lists/oss-security/2021/12/14/4"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://www.kb.cert.org/vuls/id/930724"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00646.html"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://www.debian.org/security/2021/dsa-5022"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://www.cve.org/CVERecord?id=CVE-2021-44228"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://security.gentoo.org/glsa/202310-16"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://sec.cloudapps.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-apache-log4j-qRuKNEbd"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://psirt.global.sonicwall.com/vuln-detail/SNWLID-2021-0032"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://logging.apache.org/log4j/2.x/security.html"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/SIG7FZULMNK2XF6FZRU4VWYDQXNMUGAJ"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/EOKPQGV24RRBBI4TBZUDQMM4MEH7MXCY"
|
||||
},
|
||||
{
|
||||
"type": "ADVISORY",
|
||||
"url": "https://github.com/advisories/GHSA-jfh8-c2jp-5v3q"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://cert-portal.siemens.com/productcert/pdf/ssa-714170.pdf"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://cert-portal.siemens.com/productcert/pdf/ssa-661247.pdf"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://cert-portal.siemens.com/productcert/pdf/ssa-479842.pdf"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "https://cert-portal.siemens.com/productcert/pdf/ssa-397453.pdf"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "http://www.openwall.com/lists/oss-security/2021/12/14/4"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "http://www.openwall.com/lists/oss-security/2021/12/15/3"
|
||||
},
|
||||
{
|
||||
"type": "WEB",
|
||||
"url": "http://www.openwall.com/lists/oss-security/2021/12/18/1"
|
||||
}
|
||||
],
|
||||
"affected": [
|
||||
{
|
||||
"package": {
|
||||
"name": "org.apache.logging.log4j:log4j-core",
|
||||
"ecosystem": "Maven",
|
||||
"purl": "pkg:maven/org.apache.logging.log4j/log4j-core"
|
||||
},
|
||||
"ranges": [
|
||||
{
|
||||
"type": "ECOSYSTEM",
|
||||
"events": [
|
||||
{
|
||||
"introduced": "2.13.0"
|
||||
},
|
||||
{
|
||||
"fixed": "2.16.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
"2.13.0",
|
||||
"2.13.1",
|
||||
"2.13.2",
|
||||
"2.13.3",
|
||||
"2.14.0",
|
||||
"2.14.1",
|
||||
"2.15.0"
|
||||
],
|
||||
"database_specific": {
|
||||
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2021/12/GHSA-7rjr-3q55-vv33/GHSA-7rjr-3q55-vv33.json"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": {
|
||||
"name": "org.apache.logging.log4j:log4j-core",
|
||||
"ecosystem": "Maven",
|
||||
"purl": "pkg:maven/org.apache.logging.log4j/log4j-core"
|
||||
},
|
||||
"ranges": [
|
||||
{
|
||||
"type": "ECOSYSTEM",
|
||||
"events": [
|
||||
{
|
||||
"introduced": "0"
|
||||
},
|
||||
{
|
||||
"fixed": "2.12.2"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
"2.0",
|
||||
"2.0-alpha1",
|
||||
"2.0-alpha2",
|
||||
"2.0-beta1",
|
||||
"2.0-beta2",
|
||||
"2.0-beta3",
|
||||
"2.0-beta4",
|
||||
"2.0-beta5",
|
||||
"2.0-beta6",
|
||||
"2.0-beta7",
|
||||
"2.0-beta8",
|
||||
"2.0-beta9",
|
||||
"2.0-rc1",
|
||||
"2.0-rc2",
|
||||
"2.0.1",
|
||||
"2.0.2",
|
||||
"2.1",
|
||||
"2.10.0",
|
||||
"2.11.0",
|
||||
"2.11.1",
|
||||
"2.11.2",
|
||||
"2.12.0",
|
||||
"2.12.1",
|
||||
"2.2",
|
||||
"2.3",
|
||||
"2.3.1",
|
||||
"2.3.2",
|
||||
"2.4",
|
||||
"2.4.1",
|
||||
"2.5",
|
||||
"2.6",
|
||||
"2.6.1",
|
||||
"2.6.2",
|
||||
"2.7",
|
||||
"2.8",
|
||||
"2.8.1",
|
||||
"2.8.2",
|
||||
"2.9.0",
|
||||
"2.9.1"
|
||||
],
|
||||
"database_specific": {
|
||||
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2021/12/GHSA-7rjr-3q55-vv33/GHSA-7rjr-3q55-vv33.json"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": {
|
||||
"name": "org.ops4j.pax.logging:pax-logging-log4j2",
|
||||
"ecosystem": "Maven",
|
||||
"purl": "pkg:maven/org.ops4j.pax.logging/pax-logging-log4j2"
|
||||
},
|
||||
"ranges": [
|
||||
{
|
||||
"type": "ECOSYSTEM",
|
||||
"events": [
|
||||
{
|
||||
"introduced": "1.8.0"
|
||||
},
|
||||
{
|
||||
"fixed": "1.9.2"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
"1.8.0",
|
||||
"1.8.1",
|
||||
"1.8.2",
|
||||
"1.8.3",
|
||||
"1.8.4",
|
||||
"1.8.5",
|
||||
"1.8.6",
|
||||
"1.8.7",
|
||||
"1.9.0",
|
||||
"1.9.1"
|
||||
],
|
||||
"database_specific": {
|
||||
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2021/12/GHSA-7rjr-3q55-vv33/GHSA-7rjr-3q55-vv33.json"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": {
|
||||
"name": "org.ops4j.pax.logging:pax-logging-log4j2",
|
||||
"ecosystem": "Maven",
|
||||
"purl": "pkg:maven/org.ops4j.pax.logging/pax-logging-log4j2"
|
||||
},
|
||||
"ranges": [
|
||||
{
|
||||
"type": "ECOSYSTEM",
|
||||
"events": [
|
||||
{
|
||||
"introduced": "1.10.0"
|
||||
},
|
||||
{
|
||||
"fixed": "1.10.8"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
"1.10.0",
|
||||
"1.10.1",
|
||||
"1.10.2",
|
||||
"1.10.3",
|
||||
"1.10.4",
|
||||
"1.10.5",
|
||||
"1.10.6",
|
||||
"1.10.7"
|
||||
],
|
||||
"database_specific": {
|
||||
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2021/12/GHSA-7rjr-3q55-vv33/GHSA-7rjr-3q55-vv33.json"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": {
|
||||
"name": "org.ops4j.pax.logging:pax-logging-log4j2",
|
||||
"ecosystem": "Maven",
|
||||
"purl": "pkg:maven/org.ops4j.pax.logging/pax-logging-log4j2"
|
||||
},
|
||||
"ranges": [
|
||||
{
|
||||
"type": "ECOSYSTEM",
|
||||
"events": [
|
||||
{
|
||||
"introduced": "1.11.0"
|
||||
},
|
||||
{
|
||||
"fixed": "1.11.11"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
"1.11.0",
|
||||
"1.11.1",
|
||||
"1.11.10",
|
||||
"1.11.2",
|
||||
"1.11.3",
|
||||
"1.11.4",
|
||||
"1.11.5",
|
||||
"1.11.6",
|
||||
"1.11.7",
|
||||
"1.11.8",
|
||||
"1.11.9"
|
||||
],
|
||||
"database_specific": {
|
||||
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2021/12/GHSA-7rjr-3q55-vv33/GHSA-7rjr-3q55-vv33.json"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": {
|
||||
"name": "org.ops4j.pax.logging:pax-logging-log4j2",
|
||||
"ecosystem": "Maven",
|
||||
"purl": "pkg:maven/org.ops4j.pax.logging/pax-logging-log4j2"
|
||||
},
|
||||
"ranges": [
|
||||
{
|
||||
"type": "ECOSYSTEM",
|
||||
"events": [
|
||||
{
|
||||
"introduced": "2.0.0"
|
||||
},
|
||||
{
|
||||
"fixed": "2.0.12"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
"2.0.0",
|
||||
"2.0.1",
|
||||
"2.0.10",
|
||||
"2.0.11",
|
||||
"2.0.2",
|
||||
"2.0.3",
|
||||
"2.0.4",
|
||||
"2.0.5",
|
||||
"2.0.6",
|
||||
"2.0.7",
|
||||
"2.0.8",
|
||||
"2.0.9"
|
||||
],
|
||||
"database_specific": {
|
||||
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2021/12/GHSA-7rjr-3q55-vv33/GHSA-7rjr-3q55-vv33.json"
|
||||
}
|
||||
}
|
||||
],
|
||||
"schema_version": "1.7.3",
|
||||
"severity": [
|
||||
{
|
||||
"type": "CVSS_V3",
|
||||
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"advisoryKey": "OSV-2025-npm-0001",
|
||||
"affectedPackages": [
|
||||
{
|
||||
"type": "semver",
|
||||
"identifier": "pkg:npm/%40scope%2Fleft-pad",
|
||||
"platform": "npm",
|
||||
"versionRanges": [
|
||||
{
|
||||
"fixedVersion": "2.0.0",
|
||||
"introducedVersion": "0",
|
||||
"lastAffectedVersion": null,
|
||||
"primitives": {
|
||||
"evr": null,
|
||||
"hasVendorExtensions": false,
|
||||
"nevra": null,
|
||||
"semVer": {
|
||||
"constraintExpression": null,
|
||||
"exactValue": null,
|
||||
"fixed": "2.0.0",
|
||||
"fixedInclusive": false,
|
||||
"introduced": "0",
|
||||
"introducedInclusive": true,
|
||||
"lastAffected": null,
|
||||
"lastAffectedInclusive": true,
|
||||
"style": "range"
|
||||
},
|
||||
"vendorExtensions": null
|
||||
},
|
||||
"provenance": {
|
||||
"source": "osv",
|
||||
"kind": "range",
|
||||
"value": "pkg:npm/%40scope%2Fleft-pad",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-01-08T06:30:00+00:00",
|
||||
"fieldMask": [
|
||||
"affectedpackages[].versionranges[]"
|
||||
]
|
||||
},
|
||||
"rangeExpression": null,
|
||||
"rangeKind": "semver"
|
||||
}
|
||||
],
|
||||
"normalizedVersions": [
|
||||
{
|
||||
"scheme": "semver",
|
||||
"type": "range",
|
||||
"min": "0",
|
||||
"minInclusive": true,
|
||||
"max": "2.0.0",
|
||||
"maxInclusive": false,
|
||||
"value": null,
|
||||
"notes": "osv:npm:OSV-2025-npm-0001:pkg:npm/%40scope%2Fleft-pad"
|
||||
}
|
||||
],
|
||||
"statuses": [],
|
||||
"provenance": [
|
||||
{
|
||||
"source": "osv",
|
||||
"kind": "affected",
|
||||
"value": "pkg:npm/%40scope%2Fleft-pad",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-01-08T06:30:00+00:00",
|
||||
"fieldMask": [
|
||||
"affectedpackages[]"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"CVE-2025-113",
|
||||
"GHSA-3abc-3def-3ghi",
|
||||
"OSV-2025-npm-0001",
|
||||
"OSV-RELATED-npm-42"
|
||||
],
|
||||
"canonicalMetricId": "3.1|CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
"credits": [],
|
||||
"cvssMetrics": [
|
||||
{
|
||||
"baseScore": 9.8,
|
||||
"baseSeverity": "critical",
|
||||
"provenance": {
|
||||
"source": "osv",
|
||||
"kind": "cvss",
|
||||
"value": "CVSS_V3",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-01-08T06:30:00+00:00",
|
||||
"fieldMask": []
|
||||
},
|
||||
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
"version": "3.1"
|
||||
}
|
||||
],
|
||||
"cwes": [],
|
||||
"description": "Detailed description for npm package @scope/left-pad.",
|
||||
"exploitKnown": false,
|
||||
"language": "en",
|
||||
"modified": "2025-01-08T06:30:00+00:00",
|
||||
"provenance": [
|
||||
{
|
||||
"source": "osv",
|
||||
"kind": "document",
|
||||
"value": "https://osv.dev/vulnerability/OSV-2025-npm-0001",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-01-08T07:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"advisory"
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "osv",
|
||||
"kind": "mapping",
|
||||
"value": "OSV-2025-npm-0001",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-01-08T06:30:00+00:00",
|
||||
"fieldMask": [
|
||||
"advisory"
|
||||
]
|
||||
}
|
||||
],
|
||||
"published": "2025-01-05T12:00:00+00:00",
|
||||
"references": [
|
||||
{
|
||||
"kind": "advisory",
|
||||
"provenance": {
|
||||
"source": "osv",
|
||||
"kind": "reference",
|
||||
"value": "https://example.com/npm/advisory",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-01-08T06:30:00+00:00",
|
||||
"fieldMask": [
|
||||
"references[]"
|
||||
]
|
||||
},
|
||||
"sourceTag": "ADVISORY",
|
||||
"summary": null,
|
||||
"url": "https://example.com/npm/advisory"
|
||||
},
|
||||
{
|
||||
"kind": "patch",
|
||||
"provenance": {
|
||||
"source": "osv",
|
||||
"kind": "reference",
|
||||
"value": "https://example.com/npm/fix",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-01-08T06:30:00+00:00",
|
||||
"fieldMask": [
|
||||
"references[]"
|
||||
]
|
||||
},
|
||||
"sourceTag": "FIX",
|
||||
"summary": null,
|
||||
"url": "https://example.com/npm/fix"
|
||||
}
|
||||
],
|
||||
"severity": "critical",
|
||||
"summary": "Detailed description for npm package @scope/left-pad.",
|
||||
"title": "npm package vulnerability"
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"advisoryKey": "OSV-2025-PyPI-0001",
|
||||
"affectedPackages": [
|
||||
{
|
||||
"type": "semver",
|
||||
"identifier": "pkg:pypi/requests",
|
||||
"platform": "PyPI",
|
||||
"versionRanges": [
|
||||
{
|
||||
"fixedVersion": "2.0.0",
|
||||
"introducedVersion": "0",
|
||||
"lastAffectedVersion": null,
|
||||
"primitives": {
|
||||
"evr": null,
|
||||
"hasVendorExtensions": false,
|
||||
"nevra": null,
|
||||
"semVer": {
|
||||
"constraintExpression": null,
|
||||
"exactValue": null,
|
||||
"fixed": "2.0.0",
|
||||
"fixedInclusive": false,
|
||||
"introduced": "0",
|
||||
"introducedInclusive": true,
|
||||
"lastAffected": null,
|
||||
"lastAffectedInclusive": true,
|
||||
"style": "range"
|
||||
},
|
||||
"vendorExtensions": null
|
||||
},
|
||||
"provenance": {
|
||||
"source": "osv",
|
||||
"kind": "range",
|
||||
"value": "pkg:pypi/requests",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-01-08T06:30:00+00:00",
|
||||
"fieldMask": [
|
||||
"affectedpackages[].versionranges[]"
|
||||
]
|
||||
},
|
||||
"rangeExpression": null,
|
||||
"rangeKind": "semver"
|
||||
}
|
||||
],
|
||||
"normalizedVersions": [
|
||||
{
|
||||
"scheme": "semver",
|
||||
"type": "range",
|
||||
"min": "0",
|
||||
"minInclusive": true,
|
||||
"max": "2.0.0",
|
||||
"maxInclusive": false,
|
||||
"value": null,
|
||||
"notes": "osv:PyPI:OSV-2025-PyPI-0001:pkg:pypi/requests"
|
||||
}
|
||||
],
|
||||
"statuses": [],
|
||||
"provenance": [
|
||||
{
|
||||
"source": "osv",
|
||||
"kind": "affected",
|
||||
"value": "pkg:pypi/requests",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-01-08T06:30:00+00:00",
|
||||
"fieldMask": [
|
||||
"affectedpackages[]"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"CVE-2025-114",
|
||||
"GHSA-4abc-4def-4ghi",
|
||||
"OSV-2025-PyPI-0001",
|
||||
"OSV-RELATED-PyPI-42"
|
||||
],
|
||||
"canonicalMetricId": "3.1|CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
"credits": [],
|
||||
"cvssMetrics": [
|
||||
{
|
||||
"baseScore": 9.8,
|
||||
"baseSeverity": "critical",
|
||||
"provenance": {
|
||||
"source": "osv",
|
||||
"kind": "cvss",
|
||||
"value": "CVSS_V3",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-01-08T06:30:00+00:00",
|
||||
"fieldMask": []
|
||||
},
|
||||
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
"version": "3.1"
|
||||
}
|
||||
],
|
||||
"cwes": [],
|
||||
"description": "Detailed description for PyPI package requests.",
|
||||
"exploitKnown": false,
|
||||
"language": "en",
|
||||
"modified": "2025-01-08T06:30:00+00:00",
|
||||
"provenance": [
|
||||
{
|
||||
"source": "osv",
|
||||
"kind": "document",
|
||||
"value": "https://osv.dev/vulnerability/OSV-2025-PyPI-0001",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-01-08T07:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"advisory"
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "osv",
|
||||
"kind": "mapping",
|
||||
"value": "OSV-2025-PyPI-0001",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-01-08T06:30:00+00:00",
|
||||
"fieldMask": [
|
||||
"advisory"
|
||||
]
|
||||
}
|
||||
],
|
||||
"published": "2025-01-05T12:00:00+00:00",
|
||||
"references": [
|
||||
{
|
||||
"kind": "advisory",
|
||||
"provenance": {
|
||||
"source": "osv",
|
||||
"kind": "reference",
|
||||
"value": "https://example.com/PyPI/advisory",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-01-08T06:30:00+00:00",
|
||||
"fieldMask": [
|
||||
"references[]"
|
||||
]
|
||||
},
|
||||
"sourceTag": "ADVISORY",
|
||||
"summary": null,
|
||||
"url": "https://example.com/PyPI/advisory"
|
||||
},
|
||||
{
|
||||
"kind": "patch",
|
||||
"provenance": {
|
||||
"source": "osv",
|
||||
"kind": "reference",
|
||||
"value": "https://example.com/PyPI/fix",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-01-08T06:30:00+00:00",
|
||||
"fieldMask": [
|
||||
"references[]"
|
||||
]
|
||||
},
|
||||
"sourceTag": "FIX",
|
||||
"summary": null,
|
||||
"url": "https://example.com/PyPI/fix"
|
||||
}
|
||||
],
|
||||
"severity": "critical",
|
||||
"summary": "Detailed description for PyPI package requests.",
|
||||
"title": "PyPI package vulnerability"
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
using System.Text.Json;
|
||||
using MongoDB.Bson;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Connector.Osv.Internal;
|
||||
using StellaOps.Concelier.Storage.Mongo.Documents;
|
||||
using StellaOps.Concelier.Storage.Mongo.Dtos;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Osv.Tests;
|
||||
|
||||
public sealed class OsvConflictFixtureTests
|
||||
{
|
||||
[Fact]
|
||||
public void ConflictFixture_MatchesSnapshot()
|
||||
{
|
||||
using var databaseSpecificDoc = JsonDocument.Parse("""{"severity":"medium"}""");
|
||||
|
||||
var dto = new OsvVulnerabilityDto
|
||||
{
|
||||
Id = "OSV-2025-4242",
|
||||
Summary = "Container escape for conflict-package",
|
||||
Details = "OSV captures the latest container escape details including patched version metadata.",
|
||||
Aliases = new[] { "CVE-2025-4242", "GHSA-qqqq-wwww-eeee" },
|
||||
Published = new DateTimeOffset(2025, 2, 28, 0, 0, 0, TimeSpan.Zero),
|
||||
Modified = new DateTimeOffset(2025, 3, 6, 12, 0, 0, TimeSpan.Zero),
|
||||
Severity = new[]
|
||||
{
|
||||
new OsvSeverityDto
|
||||
{
|
||||
Type = "CVSS_V3",
|
||||
Score = "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:L/I:L/A:L"
|
||||
}
|
||||
},
|
||||
References = new[]
|
||||
{
|
||||
new OsvReferenceDto
|
||||
{
|
||||
Type = "ADVISORY",
|
||||
Url = "https://osv.dev/vulnerability/OSV-2025-4242"
|
||||
},
|
||||
new OsvReferenceDto
|
||||
{
|
||||
Type = "FIX",
|
||||
Url = "https://github.com/conflict/package/commit/abcdef1234567890"
|
||||
}
|
||||
},
|
||||
Credits = new[]
|
||||
{
|
||||
new OsvCreditDto
|
||||
{
|
||||
Name = "osv-reporter",
|
||||
Type = "reporter",
|
||||
Contact = new[] { "mailto:osv-reporter@example.com" }
|
||||
}
|
||||
},
|
||||
Affected = new[]
|
||||
{
|
||||
new OsvAffectedPackageDto
|
||||
{
|
||||
Package = new OsvPackageDto
|
||||
{
|
||||
Ecosystem = "npm",
|
||||
Name = "conflict/package"
|
||||
},
|
||||
Ranges = new[]
|
||||
{
|
||||
new OsvRangeDto
|
||||
{
|
||||
Type = "SEMVER",
|
||||
Events = new[]
|
||||
{
|
||||
new OsvEventDto { Introduced = "1.0.0" },
|
||||
new OsvEventDto { LastAffected = "1.4.2" },
|
||||
new OsvEventDto { Fixed = "1.5.0" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
DatabaseSpecific = databaseSpecificDoc.RootElement.Clone()
|
||||
};
|
||||
|
||||
var document = new DocumentRecord(
|
||||
Id: Guid.Parse("8dd2b0fe-a5f5-4b3b-9f5c-0f3aad6fb6ce"),
|
||||
SourceName: OsvConnectorPlugin.SourceName,
|
||||
Uri: "https://api.osv.dev/v1/vulns/OSV-2025-4242",
|
||||
FetchedAt: new DateTimeOffset(2025, 3, 6, 11, 30, 0, TimeSpan.Zero),
|
||||
Sha256: "sha256-osv-conflict-fixture",
|
||||
Status: "completed",
|
||||
ContentType: "application/json",
|
||||
Headers: null,
|
||||
Metadata: null,
|
||||
Etag: "\"etag-osv-conflict\"",
|
||||
LastModified: new DateTimeOffset(2025, 3, 6, 12, 0, 0, TimeSpan.Zero),
|
||||
GridFsId: null);
|
||||
|
||||
var dtoRecord = new DtoRecord(
|
||||
Id: Guid.Parse("6f7d5ce7-cb47-40a5-8b41-8ad022b5fd5c"),
|
||||
DocumentId: document.Id,
|
||||
SourceName: OsvConnectorPlugin.SourceName,
|
||||
SchemaVersion: "osv.v1",
|
||||
Payload: new BsonDocument("id", dto.Id),
|
||||
ValidatedAt: new DateTimeOffset(2025, 3, 6, 12, 5, 0, TimeSpan.Zero));
|
||||
|
||||
var advisory = OsvMapper.Map(dto, document, dtoRecord, "npm");
|
||||
var snapshot = SnapshotSerializer.ToSnapshot(advisory).Replace("\r\n", "\n").TrimEnd();
|
||||
|
||||
var expectedPath = Path.Combine(AppContext.BaseDirectory, "Fixtures", "conflict-osv.canonical.json");
|
||||
var expected = File.ReadAllText(expectedPath).Replace("\r\n", "\n").TrimEnd();
|
||||
|
||||
if (!string.Equals(expected, snapshot, StringComparison.Ordinal))
|
||||
{
|
||||
var actualPath = Path.Combine(AppContext.BaseDirectory, "Fixtures", "conflict-osv.canonical.actual.json");
|
||||
File.WriteAllText(actualPath, snapshot);
|
||||
}
|
||||
|
||||
Assert.Equal(expected, snapshot);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,572 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Metrics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using MongoDB.Bson;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Connector.Common;
|
||||
using StellaOps.Concelier.Connector.Osv;
|
||||
using StellaOps.Concelier.Connector.Osv.Internal;
|
||||
using StellaOps.Concelier.Storage.Mongo.Documents;
|
||||
using StellaOps.Concelier.Storage.Mongo.Dtos;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Osv.Tests;
|
||||
|
||||
public sealed class OsvGhsaParityRegressionTests
|
||||
{
|
||||
private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web);
|
||||
|
||||
// Curated GHSA identifiers spanning multiple ecosystems (PyPI, npm/go, Maven) for parity coverage.
|
||||
private static readonly string[] GhsaIds =
|
||||
{
|
||||
"GHSA-wv4w-6qv2-qqfg", // PyPI – social-auth-app-django
|
||||
"GHSA-cjjf-27cc-pvmv", // PyPI – pyload-ng
|
||||
"GHSA-77vh-xpmg-72qh", // Go – opencontainers/image-spec
|
||||
"GHSA-7rjr-3q55-vv33" // Maven – log4j-core / pax-logging
|
||||
};
|
||||
|
||||
[Fact]
|
||||
public void FixtureParity_NoIssues_EmitsMetrics()
|
||||
{
|
||||
RegenerateFixturesIfRequested();
|
||||
|
||||
var osvAdvisories = LoadOsvAdvisories();
|
||||
var ghsaAdvisories = LoadGhsaAdvisories();
|
||||
|
||||
if (File.Exists(RebuildSentinelPath))
|
||||
{
|
||||
WriteFixture("osv-ghsa.osv.json", osvAdvisories);
|
||||
WriteFixture("osv-ghsa.ghsa.json", ghsaAdvisories);
|
||||
File.Delete(RebuildSentinelPath);
|
||||
}
|
||||
|
||||
AssertSnapshot("osv-ghsa.osv.json", osvAdvisories);
|
||||
AssertSnapshot("osv-ghsa.ghsa.json", ghsaAdvisories);
|
||||
|
||||
var measurements = new List<MeasurementRecord>();
|
||||
using var listener = CreateListener(measurements);
|
||||
|
||||
var report = OsvGhsaParityInspector.Compare(osvAdvisories, ghsaAdvisories);
|
||||
|
||||
if (report.HasIssues)
|
||||
{
|
||||
foreach (var issue in report.Issues)
|
||||
{
|
||||
Console.WriteLine($"[Parity] Issue: {issue.GhsaId} {issue.IssueKind} {issue.Detail}");
|
||||
}
|
||||
}
|
||||
|
||||
Assert.False(report.HasIssues);
|
||||
Assert.Equal(GhsaIds.Length, report.TotalGhsaIds);
|
||||
|
||||
OsvGhsaParityDiagnostics.RecordReport(report, "fixtures");
|
||||
listener.Dispose();
|
||||
|
||||
var total = Assert.Single(measurements, entry => string.Equals(entry.Instrument, "concelier.osv_ghsa.total", StringComparison.Ordinal));
|
||||
Assert.Equal(GhsaIds.Length, total.Value);
|
||||
Assert.Equal("fixtures", Assert.IsType<string>(total.Tags["dataset"]));
|
||||
|
||||
Assert.DoesNotContain(measurements, entry => string.Equals(entry.Instrument, "concelier.osv_ghsa.issues", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private static MeterListener CreateListener(List<MeasurementRecord> buffer)
|
||||
{
|
||||
var listener = new MeterListener
|
||||
{
|
||||
InstrumentPublished = (instrument, l) =>
|
||||
{
|
||||
if (instrument.Meter.Name.StartsWith("StellaOps.Concelier.Models.OsvGhsaParity", StringComparison.Ordinal))
|
||||
{
|
||||
l.EnableMeasurementEvents(instrument);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
listener.SetMeasurementEventCallback<long>((instrument, measurement, tags, state) =>
|
||||
{
|
||||
var dict = new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
dict[tag.Key] = tag.Value;
|
||||
}
|
||||
|
||||
buffer.Add(new MeasurementRecord(instrument.Name, measurement, dict));
|
||||
});
|
||||
|
||||
listener.Start();
|
||||
return listener;
|
||||
}
|
||||
|
||||
private static IReadOnlyList<Advisory> LoadOsvAdvisories()
|
||||
{
|
||||
var path = ResolveFixturePath("osv-ghsa.raw-osv.json");
|
||||
using var document = JsonDocument.Parse(File.ReadAllText(path));
|
||||
var advisories = new List<Advisory>();
|
||||
foreach (var element in document.RootElement.EnumerateArray())
|
||||
{
|
||||
advisories.Add(MapOsvAdvisory(element.GetRawText()));
|
||||
}
|
||||
advisories.Sort((a, b) => string.Compare(a.AdvisoryKey, b.AdvisoryKey, StringComparison.OrdinalIgnoreCase));
|
||||
return advisories;
|
||||
}
|
||||
|
||||
private static IReadOnlyList<Advisory> LoadGhsaAdvisories()
|
||||
{
|
||||
var path = ResolveFixturePath("osv-ghsa.raw-ghsa.json");
|
||||
using var document = JsonDocument.Parse(File.ReadAllText(path));
|
||||
var advisories = new List<Advisory>();
|
||||
foreach (var element in document.RootElement.EnumerateArray())
|
||||
{
|
||||
advisories.Add(MapGhsaAdvisory(element.GetRawText()));
|
||||
}
|
||||
advisories.Sort((a, b) => string.Compare(a.AdvisoryKey, b.AdvisoryKey, StringComparison.OrdinalIgnoreCase));
|
||||
return advisories;
|
||||
}
|
||||
|
||||
private static void RegenerateFixturesIfRequested()
|
||||
{
|
||||
var flag = Environment.GetEnvironmentVariable("UPDATE_PARITY_FIXTURES");
|
||||
Console.WriteLine($"[Parity] UPDATE_PARITY_FIXTURES={flag ?? "(null)"}");
|
||||
|
||||
var rawOsvPath = ResolveFixturePath("osv-ghsa.raw-osv.json");
|
||||
var rawGhsaPath = ResolveFixturePath("osv-ghsa.raw-ghsa.json");
|
||||
var shouldBootstrap = !File.Exists(rawOsvPath) || !File.Exists(rawGhsaPath);
|
||||
|
||||
if (!string.Equals(flag, "1", StringComparison.Ordinal) && !shouldBootstrap)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// regeneration trigger
|
||||
Console.WriteLine(shouldBootstrap
|
||||
? $"[Parity] Raw fixtures missing – regenerating OSV/GHSA snapshots for {GhsaIds.Length} advisories."
|
||||
: $"[Parity] Regenerating OSV/GHSA fixtures for {GhsaIds.Length} advisories.");
|
||||
|
||||
using var client = new HttpClient();
|
||||
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("StellaOpsParityFixtures", "1.0"));
|
||||
|
||||
var osvAdvisories = new List<Advisory>(GhsaIds.Length);
|
||||
var ghsaAdvisories = new List<Advisory>(GhsaIds.Length);
|
||||
var rawOsv = new List<JsonElement>(GhsaIds.Length);
|
||||
var rawGhsa = new List<JsonElement>(GhsaIds.Length);
|
||||
|
||||
foreach (var ghsaId in GhsaIds)
|
||||
{
|
||||
var osvJson = FetchJson(client, $"https://api.osv.dev/v1/vulns/{ghsaId}");
|
||||
var ghsaJson = FetchJson(client, $"https://api.github.com/advisories/{ghsaId}");
|
||||
|
||||
using (var osvDocument = JsonDocument.Parse(osvJson))
|
||||
{
|
||||
rawOsv.Add(osvDocument.RootElement.Clone());
|
||||
}
|
||||
using (var ghsaDocument = JsonDocument.Parse(ghsaJson))
|
||||
{
|
||||
rawGhsa.Add(ghsaDocument.RootElement.Clone());
|
||||
}
|
||||
|
||||
var osv = MapOsvAdvisory(osvJson);
|
||||
var ghsa = MapGhsaAdvisory(ghsaJson);
|
||||
|
||||
osvAdvisories.Add(osv);
|
||||
ghsaAdvisories.Add(ghsa);
|
||||
}
|
||||
|
||||
osvAdvisories.Sort((a, b) => string.Compare(a.AdvisoryKey, b.AdvisoryKey, StringComparison.OrdinalIgnoreCase));
|
||||
ghsaAdvisories.Sort((a, b) => string.Compare(a.AdvisoryKey, b.AdvisoryKey, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
WriteRawFixture("osv-ghsa.raw-osv.json", rawOsv);
|
||||
WriteRawFixture("osv-ghsa.raw-ghsa.json", rawGhsa);
|
||||
WriteFixture("osv-ghsa.osv.json", osvAdvisories);
|
||||
WriteFixture("osv-ghsa.ghsa.json", ghsaAdvisories);
|
||||
}
|
||||
|
||||
private static string FetchJson(HttpClient client, string uri)
|
||||
{
|
||||
try
|
||||
{
|
||||
return client.GetStringAsync(uri).GetAwaiter().GetResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to download '{uri}'.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static Advisory MapOsvAdvisory(string json)
|
||||
{
|
||||
var dto = JsonSerializer.Deserialize<OsvVulnerabilityDto>(json, SerializerOptions)
|
||||
?? throw new InvalidOperationException("Unable to deserialize OSV payload.");
|
||||
|
||||
var documentId = Guid.NewGuid();
|
||||
var identifier = dto.Id ?? throw new InvalidOperationException("OSV payload missing id.");
|
||||
var ecosystem = dto.Affected?.FirstOrDefault()?.Package?.Ecosystem ?? "osv";
|
||||
var fetchedAt = dto.Published ?? dto.Modified ?? DateTimeOffset.UtcNow;
|
||||
var sha = ComputeSha256Hex(json);
|
||||
|
||||
var document = new DocumentRecord(
|
||||
documentId,
|
||||
OsvConnectorPlugin.SourceName,
|
||||
$"https://osv.dev/vulnerability/{identifier}",
|
||||
fetchedAt,
|
||||
sha,
|
||||
DocumentStatuses.PendingMap,
|
||||
"application/json",
|
||||
null,
|
||||
new Dictionary<string, string>(StringComparer.Ordinal) { ["osv.ecosystem"] = ecosystem },
|
||||
null,
|
||||
dto.Modified,
|
||||
null);
|
||||
|
||||
var payload = BsonDocument.Parse(json);
|
||||
var dtoRecord = new DtoRecord(Guid.NewGuid(), document.Id, OsvConnectorPlugin.SourceName, "osv.v1", payload, DateTimeOffset.UtcNow);
|
||||
|
||||
return OsvMapper.Map(dto, document, dtoRecord, ecosystem);
|
||||
}
|
||||
|
||||
private static Advisory MapGhsaAdvisory(string json)
|
||||
{
|
||||
using var document = JsonDocument.Parse(json);
|
||||
var root = document.RootElement;
|
||||
|
||||
var ghsaId = GetString(root, "ghsa_id");
|
||||
if (string.IsNullOrWhiteSpace(ghsaId))
|
||||
{
|
||||
throw new InvalidOperationException("GHSA payload missing ghsa_id.");
|
||||
}
|
||||
|
||||
var summary = GetString(root, "summary");
|
||||
var description = GetString(root, "description");
|
||||
var severity = GetString(root, "severity")?.ToLowerInvariant();
|
||||
var published = GetDateTime(root, "published_at");
|
||||
var updated = GetDateTime(root, "updated_at");
|
||||
var recordedAt = updated ?? DateTimeOffset.UtcNow;
|
||||
|
||||
var aliases = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ghsaId };
|
||||
if (root.TryGetProperty("identifiers", out var identifiers) && identifiers.ValueKind == JsonValueKind.Array)
|
||||
{
|
||||
foreach (var identifier in identifiers.EnumerateArray())
|
||||
{
|
||||
var value = identifier.TryGetProperty("value", out var valueElem) ? valueElem.GetString() : null;
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
aliases.Add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var references = new List<AdvisoryReference>();
|
||||
if (root.TryGetProperty("references", out var referencesElem) && referencesElem.ValueKind == JsonValueKind.Array)
|
||||
{
|
||||
foreach (var referenceElem in referencesElem.EnumerateArray())
|
||||
{
|
||||
var url = referenceElem.GetString();
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var provenance = new AdvisoryProvenance("ghsa", "reference", url, recordedAt, new[] { ProvenanceFieldMasks.References });
|
||||
references.Add(new AdvisoryReference(url, DetermineReferenceKind(url), DetermineSourceTag(url), null, provenance));
|
||||
}
|
||||
}
|
||||
|
||||
references = references
|
||||
.DistinctBy(reference => reference.Url, StringComparer.OrdinalIgnoreCase)
|
||||
.OrderBy(reference => reference.Url, StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
var affectedPackages = BuildGhsaPackages(root, recordedAt);
|
||||
var cvssMetrics = BuildGhsaCvss(root, recordedAt);
|
||||
|
||||
var advisoryProvenance = new AdvisoryProvenance("ghsa", "map", ghsaId, recordedAt, new[] { ProvenanceFieldMasks.Advisory });
|
||||
|
||||
return new Advisory(
|
||||
ghsaId,
|
||||
string.IsNullOrWhiteSpace(summary) ? ghsaId : summary!,
|
||||
string.IsNullOrWhiteSpace(description) ? summary : description,
|
||||
language: "en",
|
||||
published,
|
||||
updated,
|
||||
severity,
|
||||
exploitKnown: false,
|
||||
aliases,
|
||||
references,
|
||||
affectedPackages,
|
||||
cvssMetrics,
|
||||
new[] { advisoryProvenance });
|
||||
}
|
||||
|
||||
private static IReadOnlyList<AffectedPackage> BuildGhsaPackages(JsonElement root, DateTimeOffset recordedAt)
|
||||
{
|
||||
if (!root.TryGetProperty("vulnerabilities", out var vulnerabilitiesElem) || vulnerabilitiesElem.ValueKind != JsonValueKind.Array)
|
||||
{
|
||||
return Array.Empty<AffectedPackage>();
|
||||
}
|
||||
|
||||
var packages = new List<AffectedPackage>();
|
||||
foreach (var entry in vulnerabilitiesElem.EnumerateArray())
|
||||
{
|
||||
if (!entry.TryGetProperty("package", out var packageElem) || packageElem.ValueKind != JsonValueKind.Object)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var ecosystem = GetString(packageElem, "ecosystem");
|
||||
var name = GetString(packageElem, "name");
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var identifier = BuildIdentifier(ecosystem, name);
|
||||
var packageProvenance = new AdvisoryProvenance("ghsa", "package", identifier, recordedAt, new[] { ProvenanceFieldMasks.AffectedPackages });
|
||||
|
||||
var rangeExpression = GetString(entry, "vulnerable_version_range");
|
||||
string? firstPatched = null;
|
||||
if (entry.TryGetProperty("first_patched_version", out var firstPatchedElem) && firstPatchedElem.ValueKind == JsonValueKind.Object)
|
||||
{
|
||||
firstPatched = GetString(firstPatchedElem, "identifier");
|
||||
}
|
||||
|
||||
var ranges = ParseVersionRanges(rangeExpression, firstPatched, identifier, recordedAt);
|
||||
|
||||
packages.Add(new AffectedPackage(
|
||||
AffectedPackageTypes.SemVer,
|
||||
identifier,
|
||||
ecosystem,
|
||||
ranges,
|
||||
Array.Empty<AffectedPackageStatus>(),
|
||||
new[] { packageProvenance }));
|
||||
}
|
||||
|
||||
return packages.OrderBy(package => package.Identifier, StringComparer.Ordinal).ToArray();
|
||||
}
|
||||
|
||||
private static IReadOnlyList<AffectedVersionRange> ParseVersionRanges(string? vulnerableVersionRange, string? firstPatchedVersion, string identifier, DateTimeOffset recordedAt)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(vulnerableVersionRange) && string.IsNullOrWhiteSpace(firstPatchedVersion))
|
||||
{
|
||||
return Array.Empty<AffectedVersionRange>();
|
||||
}
|
||||
|
||||
var ranges = new List<AffectedVersionRange>();
|
||||
|
||||
var expressions = vulnerableVersionRange?
|
||||
.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
|
||||
.ToArray() ?? Array.Empty<string>();
|
||||
|
||||
string? introduced = null;
|
||||
string? fixedVersion = firstPatchedVersion;
|
||||
string? lastAffected = null;
|
||||
|
||||
foreach (var expression in expressions)
|
||||
{
|
||||
if (expression.StartsWith(">=", StringComparison.Ordinal))
|
||||
{
|
||||
introduced = expression[(expression.IndexOf('=') + 1)..].Trim();
|
||||
}
|
||||
else if (expression.StartsWith(">", StringComparison.Ordinal))
|
||||
{
|
||||
introduced = expression[1..].Trim();
|
||||
}
|
||||
else if (expression.StartsWith("<=", StringComparison.Ordinal))
|
||||
{
|
||||
lastAffected = expression[(expression.IndexOf('=') + 1)..].Trim();
|
||||
}
|
||||
else if (expression.StartsWith("<", StringComparison.Ordinal))
|
||||
{
|
||||
fixedVersion = expression[1..].Trim();
|
||||
}
|
||||
}
|
||||
|
||||
var provenance = new AdvisoryProvenance("ghsa", "range", identifier, recordedAt, new[] { ProvenanceFieldMasks.VersionRanges });
|
||||
ranges.Add(new AffectedVersionRange("semver", NullIfWhitespace(introduced), NullIfWhitespace(fixedVersion), NullIfWhitespace(lastAffected), vulnerableVersionRange, provenance));
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
private static IReadOnlyList<CvssMetric> BuildGhsaCvss(JsonElement root, DateTimeOffset recordedAt)
|
||||
{
|
||||
if (!root.TryGetProperty("cvss_severities", out var severitiesElem) || severitiesElem.ValueKind != JsonValueKind.Object)
|
||||
{
|
||||
return Array.Empty<CvssMetric>();
|
||||
}
|
||||
|
||||
var metrics = new List<CvssMetric>();
|
||||
if (severitiesElem.TryGetProperty("cvss_v3", out var cvssElem) && cvssElem.ValueKind == JsonValueKind.Object)
|
||||
{
|
||||
var vector = GetString(cvssElem, "vector_string");
|
||||
if (!string.IsNullOrWhiteSpace(vector))
|
||||
{
|
||||
var score = cvssElem.TryGetProperty("score", out var scoreElem) && scoreElem.ValueKind == JsonValueKind.Number
|
||||
? scoreElem.GetDouble()
|
||||
: 0d;
|
||||
var provenance = new AdvisoryProvenance("ghsa", "cvss", vector, recordedAt, new[] { ProvenanceFieldMasks.CvssMetrics });
|
||||
var version = vector.StartsWith("CVSS:4.0", StringComparison.OrdinalIgnoreCase) ? "4.0" : "3.1";
|
||||
var severity = GetString(root, "severity")?.ToLowerInvariant() ?? "unknown";
|
||||
metrics.Add(new CvssMetric(version, vector, score, severity, provenance));
|
||||
}
|
||||
}
|
||||
|
||||
return metrics;
|
||||
}
|
||||
|
||||
private static string BuildIdentifier(string? ecosystem, string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ecosystem))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
var key = ecosystem.Trim().ToLowerInvariant();
|
||||
return key switch
|
||||
{
|
||||
"pypi" => $"pkg:pypi/{name.Replace('_', '-').ToLowerInvariant()}",
|
||||
"npm" => $"pkg:npm/{name.ToLowerInvariant()}",
|
||||
"maven" => $"pkg:maven/{name.Replace(':', '/')}",
|
||||
"go" or "golang" => $"pkg:golang/{name}",
|
||||
_ => name
|
||||
};
|
||||
}
|
||||
|
||||
private static string? DetermineReferenceKind(string url)
|
||||
{
|
||||
if (url.Contains("/commit/", StringComparison.OrdinalIgnoreCase) ||
|
||||
url.Contains("/pull/", StringComparison.OrdinalIgnoreCase) ||
|
||||
url.Contains("/releases/tag/", StringComparison.OrdinalIgnoreCase) ||
|
||||
url.Contains("/pull-requests/", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "patch";
|
||||
}
|
||||
|
||||
if (url.Contains("advisories", StringComparison.OrdinalIgnoreCase) ||
|
||||
url.Contains("security", StringComparison.OrdinalIgnoreCase) ||
|
||||
url.Contains("cve", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "advisory";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string? DetermineSourceTag(string url)
|
||||
{
|
||||
if (Uri.TryCreate(url, UriKind.Absolute, out var uri))
|
||||
{
|
||||
return uri.Host;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string? GetString(JsonElement element, string propertyName)
|
||||
{
|
||||
if (element.TryGetProperty(propertyName, out var property))
|
||||
{
|
||||
if (property.ValueKind == JsonValueKind.String)
|
||||
{
|
||||
return property.GetString();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static DateTimeOffset? GetDateTime(JsonElement element, string propertyName)
|
||||
{
|
||||
if (element.TryGetProperty(propertyName, out var property) && property.ValueKind == JsonValueKind.String)
|
||||
{
|
||||
if (property.TryGetDateTimeOffset(out var value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void WriteFixture(string filename, IReadOnlyList<Advisory> advisories)
|
||||
{
|
||||
var path = ResolveFixturePath(filename);
|
||||
var directory = Path.GetDirectoryName(path);
|
||||
if (!string.IsNullOrEmpty(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
var snapshot = SnapshotSerializer.ToSnapshot(advisories);
|
||||
File.WriteAllText(path, snapshot);
|
||||
}
|
||||
|
||||
private static void WriteRawFixture(string filename, IReadOnlyList<JsonElement> elements)
|
||||
{
|
||||
var path = ResolveFixturePath(filename);
|
||||
var directory = Path.GetDirectoryName(path);
|
||||
if (!string.IsNullOrEmpty(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
var json = JsonSerializer.Serialize(elements, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
});
|
||||
File.WriteAllText(path, json);
|
||||
}
|
||||
|
||||
private static void AssertSnapshot(string filename, IReadOnlyList<Advisory> advisories)
|
||||
{
|
||||
var path = ResolveFixturePath(filename);
|
||||
var actual = File.ReadAllText(path).Trim().ReplaceLineEndings("\n");
|
||||
var expected = SnapshotSerializer.ToSnapshot(advisories).Trim().ReplaceLineEndings("\n");
|
||||
|
||||
var normalizedActual = NormalizeRecordedAt(actual);
|
||||
var normalizedExpected = NormalizeRecordedAt(expected);
|
||||
|
||||
if (!string.Equals(normalizedExpected, normalizedActual, StringComparison.Ordinal))
|
||||
{
|
||||
var shouldUpdate = string.Equals(Environment.GetEnvironmentVariable("UPDATE_PARITY_FIXTURES"), "1", StringComparison.Ordinal);
|
||||
if (shouldUpdate)
|
||||
{
|
||||
var normalized = expected.Replace("\n", Environment.NewLine, StringComparison.Ordinal);
|
||||
File.WriteAllText(path, normalized);
|
||||
actual = expected;
|
||||
normalizedActual = normalizedExpected;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.Equal(normalizedExpected, normalizedActual);
|
||||
}
|
||||
|
||||
private static string ResolveFixturePath(string filename)
|
||||
=> Path.Combine(ProjectFixtureDirectory, filename);
|
||||
|
||||
private static string NormalizeRecordedAt(string input)
|
||||
=> RecordedAtRegex.Replace(input, "\"recordedAt\": \"#normalized#\"");
|
||||
|
||||
private static string ProjectFixtureDirectory { get; } = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "Fixtures"));
|
||||
|
||||
private static string RebuildSentinelPath => Path.Combine(ProjectFixtureDirectory, ".rebuild");
|
||||
|
||||
private static readonly Regex RecordedAtRegex = new("\"recordedAt\": \"[^\"]+\"", RegexOptions.CultureInvariant | RegexOptions.Compiled);
|
||||
|
||||
private static string ComputeSha256Hex(string payload)
|
||||
{
|
||||
var bytes = SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(payload));
|
||||
return Convert.ToHexString(bytes);
|
||||
}
|
||||
|
||||
private static string? NullIfWhitespace(string? value)
|
||||
=> string.IsNullOrWhiteSpace(value) ? null : value.Trim();
|
||||
|
||||
private sealed record MeasurementRecord(string Instrument, long Value, IReadOnlyDictionary<string, object?> Tags);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Reflection;
|
||||
using MongoDB.Bson;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Connector.Common;
|
||||
using StellaOps.Concelier.Connector.Osv;
|
||||
using StellaOps.Concelier.Connector.Osv.Internal;
|
||||
using StellaOps.Concelier.Normalization.Identifiers;
|
||||
using StellaOps.Concelier.Storage.Mongo.Documents;
|
||||
using StellaOps.Concelier.Storage.Mongo.Dtos;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Osv.Tests;
|
||||
|
||||
public sealed class OsvMapperTests
|
||||
{
|
||||
[Fact]
|
||||
public void Map_NormalizesAliasesReferencesAndRanges()
|
||||
{
|
||||
var published = DateTimeOffset.UtcNow.AddDays(-2);
|
||||
var modified = DateTimeOffset.UtcNow.AddDays(-1);
|
||||
|
||||
using var databaseSpecificJson = JsonDocument.Parse("{}");
|
||||
using var ecosystemSpecificJson = JsonDocument.Parse("{}");
|
||||
|
||||
var dto = new OsvVulnerabilityDto
|
||||
{
|
||||
Id = "OSV-2025-TEST",
|
||||
Summary = "Test summary",
|
||||
Details = "Longer details for the advisory.",
|
||||
Published = published,
|
||||
Modified = modified,
|
||||
Aliases = new[] { "CVE-2025-0001", "CVE-2025-0001", "GHSA-xxxx" },
|
||||
Related = new[] { "CVE-2025-0002" },
|
||||
References = new[]
|
||||
{
|
||||
new OsvReferenceDto { Url = "https://example.com/advisory", Type = "ADVISORY" },
|
||||
new OsvReferenceDto { Url = "https://example.com/advisory", Type = "ADVISORY" },
|
||||
new OsvReferenceDto { Url = "https://example.com/patch", Type = "PATCH" },
|
||||
},
|
||||
DatabaseSpecific = databaseSpecificJson.RootElement,
|
||||
Severity = new[]
|
||||
{
|
||||
new OsvSeverityDto { Type = "CVSS_V3", Score = "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" },
|
||||
},
|
||||
Affected = new[]
|
||||
{
|
||||
new OsvAffectedPackageDto
|
||||
{
|
||||
Package = new OsvPackageDto
|
||||
{
|
||||
Ecosystem = "PyPI",
|
||||
Name = "example",
|
||||
Purl = "pkg:pypi/example",
|
||||
},
|
||||
Ranges = new[]
|
||||
{
|
||||
new OsvRangeDto
|
||||
{
|
||||
Type = "SEMVER",
|
||||
Events = new[]
|
||||
{
|
||||
new OsvEventDto { Introduced = "0" },
|
||||
new OsvEventDto { Fixed = "1.0.1" },
|
||||
}
|
||||
}
|
||||
},
|
||||
EcosystemSpecific = ecosystemSpecificJson.RootElement,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var document = new DocumentRecord(
|
||||
Guid.NewGuid(),
|
||||
OsvConnectorPlugin.SourceName,
|
||||
"https://osv.dev/vulnerability/OSV-2025-TEST",
|
||||
DateTimeOffset.UtcNow,
|
||||
"sha256",
|
||||
DocumentStatuses.PendingParse,
|
||||
"application/json",
|
||||
null,
|
||||
new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["osv.ecosystem"] = "PyPI",
|
||||
},
|
||||
null,
|
||||
modified,
|
||||
null,
|
||||
null);
|
||||
|
||||
var payload = BsonDocument.Parse(JsonSerializer.Serialize(dto, new JsonSerializerOptions(JsonSerializerDefaults.Web)
|
||||
{
|
||||
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,
|
||||
}));
|
||||
var dtoRecord = new DtoRecord(Guid.NewGuid(), document.Id, OsvConnectorPlugin.SourceName, "osv.v1", payload, DateTimeOffset.UtcNow);
|
||||
|
||||
var advisory = OsvMapper.Map(dto, document, dtoRecord, "PyPI");
|
||||
|
||||
Assert.Equal(dto.Id, advisory.AdvisoryKey);
|
||||
Assert.Contains("CVE-2025-0002", advisory.Aliases);
|
||||
Assert.Equal(4, advisory.Aliases.Length);
|
||||
|
||||
Assert.Equal(2, advisory.References.Length);
|
||||
Assert.Equal("https://example.com/advisory", advisory.References[0].Url);
|
||||
Assert.Equal("https://example.com/patch", advisory.References[1].Url);
|
||||
|
||||
Assert.Single(advisory.AffectedPackages);
|
||||
var affected = advisory.AffectedPackages[0];
|
||||
Assert.Equal(AffectedPackageTypes.SemVer, affected.Type);
|
||||
Assert.Single(affected.VersionRanges);
|
||||
Assert.Equal("0", affected.VersionRanges[0].IntroducedVersion);
|
||||
Assert.Equal("1.0.1", affected.VersionRanges[0].FixedVersion);
|
||||
var semver = affected.VersionRanges[0].Primitives?.SemVer;
|
||||
Assert.NotNull(semver);
|
||||
Assert.Equal("0", semver!.Introduced);
|
||||
Assert.True(semver.IntroducedInclusive);
|
||||
Assert.Equal("1.0.1", semver.Fixed);
|
||||
Assert.False(semver.FixedInclusive);
|
||||
|
||||
Assert.Single(advisory.CvssMetrics);
|
||||
Assert.Equal("3.1", advisory.CvssMetrics[0].Version);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_AssignsSeverityFallbackWhenCvssVectorUnsupported()
|
||||
{
|
||||
using var databaseSpecificJson = JsonDocument.Parse("""
|
||||
{
|
||||
"severity": "MODERATE",
|
||||
"cwe_ids": ["CWE-290"]
|
||||
}
|
||||
""");
|
||||
|
||||
var dto = new OsvVulnerabilityDto
|
||||
{
|
||||
Id = "OSV-CVSS4",
|
||||
Summary = "Severity-only advisory",
|
||||
Details = "OSV entry that lacks a parsable CVSS vector.",
|
||||
Published = DateTimeOffset.UtcNow.AddDays(-10),
|
||||
Modified = DateTimeOffset.UtcNow.AddDays(-5),
|
||||
DatabaseSpecific = databaseSpecificJson.RootElement,
|
||||
Severity = new[]
|
||||
{
|
||||
new OsvSeverityDto
|
||||
{
|
||||
Type = "CVSS_V4",
|
||||
Score = "CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var (document, dtoRecord) = CreateDocumentAndDtoRecord(dto, "PyPI");
|
||||
var advisory = OsvMapper.Map(dto, document, dtoRecord, "PyPI");
|
||||
|
||||
Assert.True(advisory.CvssMetrics.IsEmpty);
|
||||
Assert.Equal("medium", advisory.Severity);
|
||||
Assert.Equal("osv:severity/medium", advisory.CanonicalMetricId);
|
||||
|
||||
var weakness = Assert.Single(advisory.Cwes);
|
||||
var provenance = Assert.Single(weakness.Provenance);
|
||||
Assert.Equal("database_specific.cwe_ids", provenance.DecisionReason);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Go", "github.com/example/project", "pkg:golang/github.com/example/project")]
|
||||
[InlineData("PyPI", "social_auth_app_django", "pkg:pypi/social-auth-app-django")]
|
||||
[InlineData("npm", "@Scope/Package", "pkg:npm/%40scope/package")]
|
||||
[InlineData("Maven", "org.example:library", "pkg:maven/org.example/library")]
|
||||
[InlineData("crates", "serde", "pkg:cargo/serde")]
|
||||
public void Map_InfersCanonicalPackageUrlWhenPurlMissing(string ecosystem, string packageName, string expectedIdentifier)
|
||||
{
|
||||
var dto = new OsvVulnerabilityDto
|
||||
{
|
||||
Id = $"OSV-{ecosystem}-PURL",
|
||||
Summary = "Test advisory",
|
||||
Details = "Details",
|
||||
Published = DateTimeOffset.UtcNow.AddDays(-1),
|
||||
Modified = DateTimeOffset.UtcNow,
|
||||
Affected = new[]
|
||||
{
|
||||
new OsvAffectedPackageDto
|
||||
{
|
||||
Package = new OsvPackageDto
|
||||
{
|
||||
Ecosystem = ecosystem,
|
||||
Name = packageName,
|
||||
Purl = null,
|
||||
},
|
||||
Ranges = null,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (string.Equals(ecosystem, "npm", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Assert.True(IdentifierNormalizer.TryNormalizePackageUrl("pkg:npm/%40scope/package", out var canonical));
|
||||
Assert.Equal(expectedIdentifier, canonical);
|
||||
}
|
||||
|
||||
var method = typeof(OsvMapper).GetMethod("DetermineIdentifier", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
Assert.NotNull(method);
|
||||
var directIdentifier = method!.Invoke(null, new object?[] { dto.Affected![0].Package!, ecosystem }) as string;
|
||||
Assert.Equal(expectedIdentifier, directIdentifier);
|
||||
|
||||
var (document, dtoRecord) = CreateDocumentAndDtoRecord(dto, ecosystem);
|
||||
var advisory = OsvMapper.Map(dto, document, dtoRecord, ecosystem);
|
||||
|
||||
var affected = Assert.Single(advisory.AffectedPackages);
|
||||
Assert.Equal(expectedIdentifier, affected.Identifier);
|
||||
}
|
||||
|
||||
private static (DocumentRecord Document, DtoRecord DtoRecord) CreateDocumentAndDtoRecord(OsvVulnerabilityDto dto, string ecosystem)
|
||||
{
|
||||
var recordedAt = DateTimeOffset.UtcNow;
|
||||
var document = new DocumentRecord(
|
||||
Guid.NewGuid(),
|
||||
OsvConnectorPlugin.SourceName,
|
||||
$"https://osv.dev/vulnerability/{dto.Id}",
|
||||
recordedAt,
|
||||
"sha256",
|
||||
DocumentStatuses.PendingParse,
|
||||
"application/json",
|
||||
null,
|
||||
new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["osv.ecosystem"] = ecosystem,
|
||||
},
|
||||
null,
|
||||
dto.Modified,
|
||||
null,
|
||||
null);
|
||||
|
||||
var payload = new BsonDocument("id", dto.Id);
|
||||
var dtoRecord = new DtoRecord(Guid.NewGuid(), document.Id, OsvConnectorPlugin.SourceName, "osv.v1", payload, recordedAt);
|
||||
return (document, dtoRecord);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using MongoDB.Bson;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Connector.Osv;
|
||||
using StellaOps.Concelier.Connector.Osv.Internal;
|
||||
using StellaOps.Concelier.Storage.Mongo.Documents;
|
||||
using StellaOps.Concelier.Storage.Mongo.Dtos;
|
||||
using StellaOps.Concelier.Connector.Common;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Osv.Tests;
|
||||
|
||||
public sealed class OsvSnapshotTests
|
||||
{
|
||||
private static readonly DateTimeOffset BaselinePublished = new(2025, 1, 5, 12, 0, 0, TimeSpan.Zero);
|
||||
private static readonly DateTimeOffset BaselineModified = new(2025, 1, 8, 6, 30, 0, TimeSpan.Zero);
|
||||
private static readonly DateTimeOffset BaselineFetched = new(2025, 1, 8, 7, 0, 0, TimeSpan.Zero);
|
||||
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public OsvSnapshotTests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("PyPI", "pkg:pypi/requests", "requests", "osv-pypi.snapshot.json")]
|
||||
[InlineData("npm", "pkg:npm/%40scope%2Fleft-pad", "@scope/left-pad", "osv-npm.snapshot.json")]
|
||||
public void Map_ProducesExpectedSnapshot(string ecosystem, string purl, string packageName, string snapshotFile)
|
||||
{
|
||||
var dto = CreateDto(ecosystem, purl, packageName);
|
||||
var document = CreateDocumentRecord(ecosystem);
|
||||
var dtoRecord = CreateDtoRecord(document, dto);
|
||||
|
||||
var advisory = OsvMapper.Map(dto, document, dtoRecord, ecosystem);
|
||||
var actual = SnapshotSerializer.ToSnapshot(advisory).Trim();
|
||||
|
||||
var snapshotPath = Path.Combine(AppContext.BaseDirectory, "Fixtures", snapshotFile);
|
||||
var expected = File.Exists(snapshotPath) ? File.ReadAllText(snapshotPath).Trim() : string.Empty;
|
||||
|
||||
if (!string.Equals(actual, expected, StringComparison.Ordinal))
|
||||
{
|
||||
_output.WriteLine(actual);
|
||||
}
|
||||
|
||||
Assert.False(string.IsNullOrEmpty(expected), $"Snapshot '{snapshotFile}' not found or empty.");
|
||||
|
||||
using var expectedJson = JsonDocument.Parse(expected);
|
||||
using var actualJson = JsonDocument.Parse(actual);
|
||||
Assert.True(JsonElement.DeepEquals(actualJson.RootElement, expectedJson.RootElement), "OSV snapshot mismatch.");
|
||||
}
|
||||
|
||||
private static OsvVulnerabilityDto CreateDto(string ecosystem, string purl, string packageName)
|
||||
{
|
||||
return new OsvVulnerabilityDto
|
||||
{
|
||||
Id = $"OSV-2025-{ecosystem}-0001",
|
||||
Summary = $"{ecosystem} package vulnerability",
|
||||
Details = $"Detailed description for {ecosystem} package {packageName}.",
|
||||
Published = BaselinePublished,
|
||||
Modified = BaselineModified,
|
||||
Aliases = new[] { $"CVE-2025-11{ecosystem.Length}", $"GHSA-{ecosystem.Length}abc-{ecosystem.Length}def-{ecosystem.Length}ghi" },
|
||||
Related = new[] { $"OSV-RELATED-{ecosystem}-42" },
|
||||
References = new[]
|
||||
{
|
||||
new OsvReferenceDto { Url = $"https://example.com/{ecosystem}/advisory", Type = "ADVISORY" },
|
||||
new OsvReferenceDto { Url = $"https://example.com/{ecosystem}/fix", Type = "FIX" },
|
||||
},
|
||||
Severity = new[]
|
||||
{
|
||||
new OsvSeverityDto { Type = "CVSS_V3", Score = "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" },
|
||||
},
|
||||
Affected = new[]
|
||||
{
|
||||
new OsvAffectedPackageDto
|
||||
{
|
||||
Package = new OsvPackageDto
|
||||
{
|
||||
Ecosystem = ecosystem,
|
||||
Name = packageName,
|
||||
Purl = purl,
|
||||
},
|
||||
Ranges = new[]
|
||||
{
|
||||
new OsvRangeDto
|
||||
{
|
||||
Type = "SEMVER",
|
||||
Events = new[]
|
||||
{
|
||||
new OsvEventDto { Introduced = "0" },
|
||||
new OsvEventDto { Fixed = "2.0.0" },
|
||||
}
|
||||
}
|
||||
},
|
||||
Versions = new[] { "1.0.0", "1.5.0" },
|
||||
EcosystemSpecific = ParseElement("{\"severity\":\"high\"}"),
|
||||
}
|
||||
},
|
||||
DatabaseSpecific = ParseElement("{\"source\":\"osv.dev\"}"),
|
||||
};
|
||||
}
|
||||
|
||||
private static DocumentRecord CreateDocumentRecord(string ecosystem)
|
||||
=> new(
|
||||
Guid.Parse("11111111-1111-1111-1111-111111111111"),
|
||||
OsvConnectorPlugin.SourceName,
|
||||
$"https://osv.dev/vulnerability/OSV-2025-{ecosystem}-0001",
|
||||
BaselineFetched,
|
||||
"sha256-osv-snapshot",
|
||||
DocumentStatuses.PendingParse,
|
||||
"application/json",
|
||||
null,
|
||||
new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["osv.ecosystem"] = ecosystem,
|
||||
},
|
||||
"\"osv-etag\"",
|
||||
BaselineModified,
|
||||
null,
|
||||
null);
|
||||
|
||||
private static DtoRecord CreateDtoRecord(DocumentRecord document, OsvVulnerabilityDto dto)
|
||||
{
|
||||
var payload = BsonDocument.Parse(JsonSerializer.Serialize(dto, new JsonSerializerOptions(JsonSerializerDefaults.Web)
|
||||
{
|
||||
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,
|
||||
}));
|
||||
|
||||
return new DtoRecord(Guid.Parse("22222222-2222-2222-2222-222222222222"), document.Id, OsvConnectorPlugin.SourceName, "osv.v1", payload, BaselineModified);
|
||||
}
|
||||
|
||||
private static JsonElement ParseElement(string json)
|
||||
{
|
||||
using var document = JsonDocument.Parse(json);
|
||||
return document.RootElement.Clone();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../StellaOps.Concelier.Models/StellaOps.Concelier.Models.csproj" />
|
||||
<ProjectReference Include="../StellaOps.Concelier.Connector.Common/StellaOps.Concelier.Connector.Common.csproj" />
|
||||
<ProjectReference Include="../StellaOps.Concelier.Connector.Osv/StellaOps.Concelier.Connector.Osv.csproj" />
|
||||
<ProjectReference Include="../StellaOps.Concelier.Storage.Mongo/StellaOps.Concelier.Storage.Mongo.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Fixtures\*.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user