Skip to content

Commit

Permalink
TC-2223 OSV GHSA - Ecosystem npm
Browse files Browse the repository at this point in the history
Signed-off-by: mrizzi <[email protected]>
  • Loading branch information
mrizzi committed Feb 6, 2025
1 parent 8c8c367 commit c84890b
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 23 deletions.
1 change: 1 addition & 0 deletions entity/src/version_scheme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ pub enum VersionScheme {
Python,
Maven,
Golang,
Npm,
}
9 changes: 8 additions & 1 deletion etc/test-data/cyclonedx/ghsa_test.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@
"version": "1.1.0",
"description": "1 vulnerability",
"purl": "pkg:golang/code.gitea.io/[email protected]"
},
{
"type": "library",
"name": "passport",
"version": "2.1.0",
"description": "1 vulnerability",
"purl": "pkg:npm/%40fastify/[email protected]"
}
]
}
}
92 changes: 92 additions & 0 deletions etc/test-data/osv/GHSA-2ccf-ffrj-m4qw.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"schema_version": "1.4.0",
"id": "GHSA-2ccf-ffrj-m4qw",
"modified": "2023-04-24T15:56:27Z",
"published": "2023-04-21T22:32:47Z",
"aliases": [
"CVE-2023-29020"
],
"summary": "CSRF token fixation in fastify-passport",
"details": "The [CSRF](https://owasp.org/www-community/attacks/csrf) protection enforced by the `@fastify/csrf-protection` library, when combined with `@fastify/passport`, can be bypassed by network and same-site attackers.\n\n## Details\n`fastify/csrf-protection` implements the [synchronizer token pattern](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#synchronizer-token-pattern) (using plugins `@fastify/session` and `@fastify/secure-session`) by storing a random value used for CSRF token generation in the `_csrf` attribute of a user's session.\n\nThe `@fastify/passport` library does not clear the session object upon authentication, preserving the `_csrf` attribute between pre-login and authenticated sessions. Consequently, CSRF tokens generated before authentication are still valid. Network and [same-site attackers](https://canitakeyoursubdomain.name/) can thus obtain a CSRF token for their pre-session, fixate that pre-session in the victim's browser via cookie tossing, and then perform a CSRF attack after the victim authenticates.\n\n## Fix\nAs a solution, newer versions of `@fastify/passport` include the configuration options\n\n* `clearSessionOnLogin (default: true)` and\n* `clearSessionIgnoreFields (default: ['session'])`\n\nto clear all the session attributes by default, preserving those explicitly defined in `clearSessionIgnoreFields`.\n\n## Credits\n* Pedro Adão (@pedromigueladao), [Instituto Superior Técnico, University of Lisbon](https://tecnico.ulisboa.pt/)\n* Marco Squarcina (@lavish), [Security & Privacy Research Unit, TU Wien](https://secpriv.wien/)",
"severity": [
{
"type": "CVSS_V3",
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N"
}
],
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "@fastify/passport"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"fixed": "1.1.0"
}
]
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "@fastify/passport"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "2.0.0"
},
{
"fixed": "2.3.0"
}
]
}
]
}
],
"references": [
{
"type": "WEB",
"url": "https://github.com/fastify/fastify-passport/security/advisories/GHSA-2ccf-ffrj-m4qw"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-29020"
},
{
"type": "WEB",
"url": "https://github.com/fastify/fastify-passport/commit/07c90feab9cba0dd4779e47cfb0717a7e2f01d3d"
},
{
"type": "WEB",
"url": "https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#synchronizer-token-pattern"
},
{
"type": "PACKAGE",
"url": "https://github.com/fastify/fastify-passport"
},
{
"type": "WEB",
"url": "https://owasp.org/www-community/attacks/csrf"
}
],
"database_specific": {
"cwe_ids": [
"CWE-352"
],
"severity": "MODERATE",
"github_reviewed": true,
"github_reviewed_at": "2023-04-21T22:32:47Z",
"nvd_published_at": "2023-04-21T23:15:20Z"
}
}
13 changes: 11 additions & 2 deletions modules/fundamental/tests/sbom/details.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ async fn sbom_details_cyclonedx_osv(ctx: &TrustifyContext) -> Result<(), anyhow:
Some("urn:uuid:a5ddee00-4b86-498c-b7fd-b001b77479d1".to_string())
);

// ingest the advisory
// ingest the advisories
let pypi = ctx.ingest_document("osv/GHSA-45c4-8wx5-qw6w.json").await?;

assert_eq!(pypi.document_id, Some("GHSA-45c4-8wx5-qw6w".to_string()));
Expand All @@ -35,13 +35,16 @@ async fn sbom_details_cyclonedx_osv(ctx: &TrustifyContext) -> Result<(), anyhow:
let go = ctx.ingest_document("osv/GHSA-4h4p-553m-46qh.json").await?;
assert_eq!(go.document_id, Some("GHSA-4h4p-553m-46qh".to_string()));

let npm = ctx.ingest_document("osv/GHSA-2ccf-ffrj-m4qw.json").await?;
assert_eq!(npm.document_id, Some("GHSA-2ccf-ffrj-m4qw".to_string()));

let sbom1 = sbom
.fetch_sbom_details(result1.id, vec![], &ctx.db)
.await?
.expect("SBOM details must be found");
log::info!("SBOM1: {sbom1:?}");

assert_eq!(3, sbom1.advisories.len());
assert_eq!(4, sbom1.advisories.len());
check_advisory(
&sbom1,
"GHSA-45c4-8wx5-qw6w",
Expand All @@ -60,6 +63,12 @@ async fn sbom_details_cyclonedx_osv(ctx: &TrustifyContext) -> Result<(), anyhow:
"CVE-2024-6886",
Severity::Critical,
);
check_advisory(
&sbom1,
"GHSA-2ccf-ffrj-m4qw",
"CVE-2023-29020",
Severity::High,
);
Ok(())
}

Expand Down
10 changes: 10 additions & 0 deletions modules/ingestor/src/service/advisory/osv/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,16 @@ impl<'g> OsvLoader<'g> {
)
.await?;
}
(RangeType::Ecosystem, Ecosystem::Npm) => {
create_package_status(
&advisory_vuln,
&purl,
range,
&VersionScheme::Npm,
&tx,
)
.await?;
}
(_, _) => {
create_package_status_versions(
&advisory_vuln,
Expand Down
45 changes: 25 additions & 20 deletions modules/ingestor/src/service/advisory/osv/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn translate<'a>(ecosystem: &Ecosystem, name: &'a str) -> Option<PackageUrl<'a>>
match ecosystem {
Ecosystem::CRAN => PackageUrl::new("cran", name).ok(),
Ecosystem::CratesIO => PackageUrl::new("cargo", name).ok(),
Ecosystem::Npm => PackageUrl::new("npm", name).ok(),
Ecosystem::Npm => split_name(name, "npm", "/"),
Ecosystem::Maven(repo) => {
let split = name.split(':').collect::<Vec<_>>();
if split.len() == 2 {
Expand All @@ -39,29 +39,29 @@ fn translate<'a>(ecosystem: &Ecosystem, name: &'a str) -> Option<PackageUrl<'a>>
}
}
Ecosystem::PyPI => PackageUrl::new("pypi", name).ok(),
Ecosystem::Go => {
let ty = "golang";
let separator = "/";
let split = name.split(separator).collect::<Vec<_>>();
match split.len() {
0 => None,
1 => PackageUrl::new(ty, split[0]).ok(),
_ => {
let namespace = split[0];
let name = split[1..].join(separator);
PackageUrl::new(ty, name)
.map(|mut purl| {
purl.with_namespace(namespace);
purl
})
.ok()
}
}
}
Ecosystem::Go => split_name(name, "golang", "/"),
_ => None,
}
}

fn split_name<'a>(name: &'a str, ty: &'a str, separator: &str) -> Option<PackageUrl<'a>> {
let split = name.split(separator).collect::<Vec<_>>();
match split.len() {
0 => None,
1 => PackageUrl::new(ty, split[0]).ok(),
_ => {
let namespace = split[0];
let name = split[1..].join(separator);
PackageUrl::new(ty, name)
.map(|mut purl| {
purl.with_namespace(namespace);
purl
})
.ok()
}
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down Expand Up @@ -91,6 +91,11 @@ mod test {
"github.com/minio/minio",
Some("pkg:golang/github.com/minio/minio")
)]
#[case(
Ecosystem::Npm,
"@fastify/passport",
Some("pkg:npm/%40fastify/passport")
)]
fn test_translate(
#[case] ecosystem: Ecosystem,
#[case] name: &str,
Expand Down

0 comments on commit c84890b

Please sign in to comment.