2025-11-07 18:01:57 +00:00
module . exports = {
friendlyName : 'View dashboard' ,
description : 'Display "Dashboard" page.' ,
exits : {
success : {
viewTemplatePath : 'pages/dashboard'
}
} ,
fn : async function ( ) {
// console.time(`Dashboard page view action`);
let dataForGraphs = { } ;
// Get the most recently created Vulnerability and VulnerabilityInstall record.
let latestVulnerabilityInstallRecord = await VulnerabilityInstall . find ( ) . sort ( 'updatedAt DESC' ) . limit ( 1 ) ;
let latestVulnerabilityRecord = await Vulnerability . find ( ) . sort ( 'updatedAt DESC' ) . limit ( 1 ) ;
// Get the most recent createdAt timestamp from these records, we'll use this timestamp to set the "Last updated:" on the dashboard page.
let latestTimestamp = Math . max ( latestVulnerabilityRecord [ 0 ] . updatedAt , latestVulnerabilityInstallRecord [ 0 ] . updatedAt ) ;
let dashboardDataLastUpdatedAt = latestTimestamp ;
dataForGraphs . lastUpdatedAt = dashboardDataLastUpdatedAt ;
//
// ╦ ╦╦ ╦╦ ╔╗╔╔═╗╦═╗╔═╗╔╗ ╦╦ ╦╔╦╗╦ ╦ ╔═╗╔═╗╦ ╦╔╗╔╔╦╗╔═╗
// ╚╗╔╝║ ║║ ║║║║╣ ╠╦╝╠═╣╠╩╗║║ ║ ║ ╚╦╝ ║ ║ ║║ ║║║║ ║ ╚═╗
// ╚╝ ╚═╝╩═╝╝╚╝╚═╝╩╚═╩ ╩╚═╝╩╩═╝╩ ╩ ╩ ╚═╝╚═╝╚═╝╝╚╝ ╩ ╚═╝
// Note: the information gathered in this section is used in the unique vulnerability count tiles, as well as the "What percentage are critical?" chart.
let nativeQueryToFindAllVulnerabilityIdsWithSeverity ;
if ( sails . config . datastores . default . adapter === 'sails-postgresql' ) {
nativeQueryToFindAllVulnerabilityIdsWithSeverity = `
SELECT
vulnerability . id ,
vulnerability . severity
FROM vulnerability
WHERE EXISTS (
SELECT 1
FROM vulnerabilityinstall
WHERE vulnerabilityinstall . vulnerability = vulnerability . id
AND ( vulnerabilityinstall . "uninstalledAt" IS NULL OR vulnerabilityinstall . "uninstalledAt" = 0 )
) ; ` ;
} else {
nativeQueryToFindAllVulnerabilityIdsWithSeverity = `
SELECT
vulnerability . id ,
vulnerability . severity
FROM vulnerability
WHERE EXISTS (
SELECT 1
FROM vulnerabilityinstall
WHERE vulnerabilityinstall . vulnerability = vulnerability . id
AND ( vulnerabilityinstall . uninstalledAt IS NULL
OR vulnerabilityinstall . uninstalledAt = 0 )
) ; ` ;
}
// console.time('all vulns native query');
let vulnerabilityNativeQueryResult = await sails . sendNativeQuery ( nativeQueryToFindAllVulnerabilityIdsWithSeverity ) ;
// console.timeEnd('all vulns native query');
let vulnerabilityIdsWithSeverity = vulnerabilityNativeQueryResult . rows ;
// Sort the vulnerabilities by severity, and add the counts to the totalUniqueCounts dictionary.
let criticalSeverity = vulnerabilityIdsWithSeverity . filter ( ( vuln ) => {
return vuln . severity >= 9 ;
} ) ;
let highSeverity = vulnerabilityIdsWithSeverity . filter ( ( vuln ) => {
return vuln . severity <= 8.9 && vuln . severity >= 7.0 ;
} ) ;
let mediumSeverity = vulnerabilityIdsWithSeverity . filter ( ( vuln ) => {
return vuln . severity <= 6.9 && vuln . severity >= 4.0 ;
} ) ;
let lowSeverity = vulnerabilityIdsWithSeverity . filter ( ( vuln ) => {
return vuln . severity >= 0 && vuln . severity <= 3.9 ;
} ) ;
let totalUniqueCounts = {
low : lowSeverity . length ,
medium : mediumSeverity . length ,
high : highSeverity . length ,
critical : criticalSeverity . length ,
} ;
dataForGraphs . totalUniqueCounts = totalUniqueCounts ;
// Now build native SQL Queries using the IDs of vulnerabilities to find vulnerabilityInstall records for each severity.
let lowVulnerabilityInstallNativeQuery ;
let mediumVulnerabilityInstallNativeQuery ;
let highVulnerabilityInstallNativeQuery ;
let criticalVulnerabilityInstallNativeQuery ;
if ( sails . config . datastores . default . adapter === 'sails-postgresql' ) {
// If this app is configured to use a Postgres datastore, we'll need to put double quotes around the uninstalledAt column name.
lowVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE "uninstalledAt" = 0 AND vulnerability IN ( $ { _ . pluck ( lowSeverity , 'id' ) . join ( ',' ) } ) ; ` ;
mediumVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE "uninstalledAt" = 0 AND vulnerability IN ( $ { _ . pluck ( mediumSeverity , 'id' ) . join ( ',' ) } ) ` ;
highVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE "uninstalledAt" = 0 AND vulnerability IN ( $ { _ . pluck ( highSeverity , 'id' ) . join ( ',' ) } ) ` ;
criticalVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE "uninstalledAt" = 0 AND vulnerability IN ( $ { _ . pluck ( criticalSeverity , 'id' ) . join ( ',' ) } ) ` ;
} else if ( sails . config . datastores . default . adapter === 'sails-mysql' ) {
lowVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE uninstalledAt = 0 AND vulnerability IN ( $ { _ . pluck ( lowSeverity , 'id' ) . join ( ',' ) } ) ` ;
mediumVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE uninstalledAt = 0 AND vulnerability IN ( $ { _ . pluck ( mediumSeverity , 'id' ) . join ( ',' ) } ) ` ;
highVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE uninstalledAt = 0 AND vulnerability IN ( $ { _ . pluck ( highSeverity , 'id' ) . join ( ',' ) } ) ` ;
criticalVulnerabilityInstallNativeQuery = `
SELECT * FROM vulnerabilityinstall
WHERE uninstalledAt = 0 AND vulnerability IN ( $ { _ . pluck ( criticalSeverity , 'id' ) . join ( ',' ) } ) ` ;
}
// console.time(`native queries to get total counts`);
// Now send some queries.
let criticalVulnInstallsResult = await sails . sendNativeQuery ( criticalVulnerabilityInstallNativeQuery ) ;
let totalInstallsWithCricitalVulns = criticalVulnInstallsResult . rows ;
let highVulnInstallsResult = await sails . sendNativeQuery ( highVulnerabilityInstallNativeQuery ) ;
let totalInstallsWithHighVulns = highVulnInstallsResult . rows ;
let mediumVulnInstallsResult = await sails . sendNativeQuery ( mediumVulnerabilityInstallNativeQuery ) ;
let totalInstallsWithMediumVulns = mediumVulnInstallsResult . rows ;
let lowVulnInstallsResult = await sails . sendNativeQuery ( lowVulnerabilityInstallNativeQuery ) ;
let totalInstallsWithLowVulns = lowVulnInstallsResult . rows ;
// console.timeEnd(`native queries to get total counts`);
let totalNumberOfVulns = {
low : totalInstallsWithLowVulns . length ,
medium : totalInstallsWithMediumVulns . length ,
high : totalInstallsWithHighVulns . length ,
critical : totalInstallsWithCricitalVulns . length
} ;
dataForGraphs . totalNumberOfVulns = totalNumberOfVulns ;
// ╔╦╗╦ ╦╔═╗ ╦═╗╦╔═╗╦╔═╦╔═╗╔═╗╔╦╗ ╦ ╦╔═╗╔═╗╔╦╗╔═╗ ╦═╗╦╔═╗╦ ╦╔╦╗ ╔╗╔╔═╗╦ ╦
// ║ ╠═╣║╣ ╠╦╝║╚═╗╠╩╗║║╣ ╚═╗ ║ ╠═╣║ ║╚═╗ ║ ╚═╗ ╠╦╝║║ ╦╠═╣ ║ ║║║║ ║║║║
// ╩ ╩ ╩╚═╝ ╩╚═╩╚═╝╩ ╩╩╚═╝╚═╝ ╩ ╩ ╩╚═╝╚═╝ ╩ ╚═╝ ╩╚═╩╚═╝╩ ╩ ╩ ╝╚╝╚═╝╚╩╝
let nativeQueryToFindTopTenMostVulnerableHosts ;
if ( sails . config . datastores . default . adapter === 'sails-postgresql' ) {
nativeQueryToFindTopTenMostVulnerableHosts = `
WITH "installAggregates" AS (
SELECT
vulnerabilityinstall . vulnerability AS "vulnerabilityId" ,
COUNT ( DISTINCT CASE
WHEN vulnerabilityinstall . "uninstalledAt" IS NULL OR vulnerabilityinstall . "uninstalledAt" = 0
THEN vulnerabilityinstall . host END
) AS "currentAffectedHostCount" ,
COUNT ( DISTINCT vulnerabilityinstall . host ) AS "totalAffectedHostCount"
FROM vulnerabilityinstall
GROUP BY vulnerabilityinstall . vulnerability
) ,
"riskCalculation" AS (
SELECT
vulnerability . id AS "vulnerabilityId" ,
"installAggregates" . "currentAffectedHostCount" ,
"installAggregates" . "totalAffectedHostCount" ,
(
vulnerability . severity *
CASE
WHEN vulnerability . "hasKnownExploit" THEN 2.0
WHEN vulnerability . "probabilityOfExploit" > 0.5 THEN 1.5
ELSE 1.0
END
) AS "threatScore" ,
LN ( 1 + COALESCE ( "installAggregates" . "currentAffectedHostCount" , 0 ) ) AS "impactScore"
FROM vulnerability
LEFT JOIN "installAggregates"
ON "installAggregates" . "vulnerabilityId" = vulnerability . id
) ,
"normalizedRisk" AS (
SELECT
"vulnerabilityId" ,
( "threatScore" * "impactScore" ) AS "rawRiskScore" ,
MAX ( "threatScore" * "impactScore" ) OVER ( ) AS "maxRawRisk"
FROM "riskCalculation"
) ,
"vulnerabilityPps" AS (
SELECT
"vulnerabilityId" ,
CASE
WHEN "maxRawRisk" > 0
THEN ( "rawRiskScore" / "maxRawRisk" * 9.9 ) + 0.1
ELSE 0.1
END AS "vulnerabilityPps"
FROM "normalizedRisk"
) ,
"hostVulnerabilitySet" AS (
SELECT DISTINCT
vulnerabilityinstall . host AS "hostId" ,
vulnerability . id AS "vulnerabilityId" ,
vulnerability . "hasKnownExploit" AS "hasKnownExploit" ,
"vulnerabilityPps" . "vulnerabilityPps" AS "vulnerabilityPps"
FROM vulnerabilityinstall
JOIN vulnerability
ON vulnerability . id = vulnerabilityinstall . vulnerability
JOIN "vulnerabilityPps"
ON "vulnerabilityPps" . "vulnerabilityId" = vulnerability . id
WHERE vulnerabilityinstall . "uninstalledAt" IS NULL
OR vulnerabilityinstall . "uninstalledAt" = 0
) ,
"hostPps" AS (
SELECT
host . "displayName" ,
host . "fleetApid" ,
COUNT ( DISTINCT "hostVulnerabilitySet" . "vulnerabilityId" ) AS "vulnerabilityCount" ,
COUNT ( DISTINCT "hostVulnerabilitySet" . "vulnerabilityId" ) FILTER ( WHERE "hostVulnerabilitySet" . "hasKnownExploit" ) AS "kevCount" ,
MAX ( "hostVulnerabilitySet" . "vulnerabilityPps" ) AS "maxVulnerabilityPps" ,
(
MAX ( "hostVulnerabilitySet" . "vulnerabilityPps" )
* ( 1 + LN ( 1 + COUNT ( DISTINCT "hostVulnerabilitySet" . "vulnerabilityId" ) ) * 0.15 )
) : : numeric ( 12 , 4 ) AS "hostPpsNumeric"
FROM "hostVulnerabilitySet"
JOIN host ON host . id = "hostVulnerabilitySet" . "hostId"
GROUP BY host . "displayName" , host . "fleetApid"
) ,
"hostPpsNormalized" AS (
SELECT
"hostPps" . "displayName" ,
"hostPps" . "fleetApid" ,
"hostPps" . "vulnerabilityCount" ,
"hostPps" . "kevCount" ,
"hostPps" . "maxVulnerabilityPps" ,
"hostPps" . "hostPpsNumeric" ,
MAX ( "hostPps" . "hostPpsNumeric" ) OVER ( ) AS "maxHostPps"
FROM "hostPps"
)
SELECT
"hostPpsNormalized" . "displayName" ,
"hostPpsNormalized" . "fleetApid" ,
"hostPpsNormalized" . "vulnerabilityCount" ,
"hostPpsNormalized" . "kevCount" ,
ROUND ( "hostPpsNormalized" . "maxVulnerabilityPps" : : numeric , 2 ) AS "worstVulnerabilityPps" ,
CASE
WHEN "hostPpsNormalized" . "maxHostPps" > 0
THEN ROUND ( ( "hostPpsNormalized" . "hostPpsNumeric" / "hostPpsNormalized" . "maxHostPps" ) * 9 + 1 , 2 )
ELSE 1.00
END AS "hostPps"
FROM "hostPpsNormalized"
ORDER BY "hostPps" DESC , "hostPpsNormalized" . "displayName" ASC
LIMIT 10 ; ` ;
} else {
nativeQueryToFindTopTenMostVulnerableHosts = `
WITH installAggregates AS (
SELECT
vi . vulnerability AS vulnerabilityId ,
COUNT ( DISTINCT IF ( vi . uninstalledAt IS NULL OR vi . uninstalledAt = 0 , vi . host , NULL ) ) AS currentAffectedHostCount ,
COUNT ( DISTINCT vi . host ) AS totalAffectedHostCount
FROM vulnerabilityinstall vi
GROUP BY vi . vulnerability
) ,
riskCalculation AS (
SELECT
v . id AS vulnerabilityId ,
ia . currentAffectedHostCount ,
ia . totalAffectedHostCount ,
(
v . severity *
CASE
WHEN v . hasKnownExploit THEN 2.0
WHEN v . probabilityOfExploit > 0.5 THEN 1.5
ELSE 1.0
END
) AS threatScore ,
LN ( 1 + COALESCE ( ia . currentAffectedHostCount , 0 ) ) AS impactScore
FROM vulnerability v
LEFT JOIN installAggregates ia ON ia . vulnerabilityId = v . id
) ,
normalizedRisk AS (
SELECT
vulnerabilityId ,
( threatScore * impactScore ) AS rawRiskScore ,
MAX ( threatScore * impactScore ) OVER ( ) AS maxRawRisk
FROM riskCalculation
) ,
vulnerabilityPps AS (
SELECT
vulnerabilityId ,
CASE
WHEN maxRawRisk > 0
THEN ( rawRiskScore / maxRawRisk * 9.9 ) + 0.1
ELSE 0.1
END AS vulnerabilityPps
FROM normalizedRisk
) ,
hostVulnerabilitySet AS (
SELECT DISTINCT
vi . host AS hostId ,
v . id AS vulnerabilityId ,
v . hasKnownExploit AS hasKnownExploit ,
vp . vulnerabilityPps AS vulnerabilityPps
FROM vulnerabilityinstall vi
JOIN vulnerability v ON v . id = vi . vulnerability
JOIN vulnerabilityPps vp ON vp . vulnerabilityId = v . id
WHERE vi . uninstalledAt IS NULL OR vi . uninstalledAt = 0
) ,
hostPps AS (
SELECT
h . displayName ,
h . fleetApid ,
COUNT ( DISTINCT hvs . vulnerabilityId ) AS vulnerabilityCount ,
COUNT ( DISTINCT IF ( hvs . hasKnownExploit , hvs . vulnerabilityId , NULL ) ) AS kevCount ,
MAX ( hvs . vulnerabilityPps ) AS maxVulnerabilityPps ,
CAST (
MAX ( hvs . vulnerabilityPps ) * ( 1 + LN ( 1 + COUNT ( DISTINCT hvs . vulnerabilityId ) ) * 0.15 )
AS DECIMAL ( 12 , 4 )
) AS hostPpsNumeric
FROM hostVulnerabilitySet hvs
JOIN host h ON h . id = hvs . hostId
GROUP BY h . displayName , h . fleetApid
) ,
hostPpsNormalized AS (
SELECT
hp . displayName ,
hp . fleetApid ,
hp . vulnerabilityCount ,
hp . kevCount ,
hp . maxVulnerabilityPps ,
hp . hostPpsNumeric ,
MAX ( hp . hostPpsNumeric ) OVER ( ) AS maxHostPps
FROM hostPps hp
)
SELECT
displayName ,
fleetApid ,
vulnerabilityCount ,
kevCount ,
ROUND ( maxVulnerabilityPps , 2 ) AS worstVulnerabilityPps ,
CASE
WHEN maxHostPps > 0
THEN ROUND ( ( ( hostPpsNumeric / maxHostPps ) * 9 ) + 1 , 2 )
ELSE 1.00
END AS hostPps
FROM hostPpsNormalized
ORDER BY hostPps DESC , displayName ASC
LIMIT 10 ; ` ;
}
// console.time(`native query to find top 10 most vulnerable hosts`);
let topTenMostVulnerableHosts = await sails . sendNativeQuery ( nativeQueryToFindTopTenMostVulnerableHosts ) ;
// console.timeEnd(`native query to find top 10 most vulnerable hosts`);
// console.log(topTenMostVulnerableHosts.rows);
let mostVulnerableHosts = topTenMostVulnerableHosts . rows . map ( ( host ) => {
return {
displayName : host . displayName ,
fleetUrl : sails . config . custom . fleetBaseUrl + ` /hosts/ ${ host . fleetApid } ` ,
numberOfCves : host . vulnerabilityCount ,
pps : host . hostPps ,
} ;
} ) ;
dataForGraphs . mostVulnerableHosts = mostVulnerableHosts ;
// ╔╦╗╦ ╦╔═╗ ╦ ╦╔═╗╦ ╦╔═╗╦ ╔═╗╦ ╦╔═╗╔═╗╔═╗╔═╗╔╦╗╔═╗ ╦╔╗╔ ╔═╗╔═╗╔═╗╔╦╗╦ ╦╔═╗╦═╗╔═╗
// ║ ╠═╣║╣ ║ ║╚═╗║ ║╠═╣║ ╚═╗║ ║╚═╗╠═╝║╣ ║ ║ ╚═╗ ║║║║ ╚═╗║ ║╠╣ ║ ║║║╠═╣╠╦╝║╣
// ╩ ╩ ╩╚═╝ ╚═╝╚═╝╚═╝╩ ╩╩═╝ ╚═╝╚═╝╚═╝╩ ╚═╝╚═╝ ╩ ╚═╝ ╩╝╚╝ ╚═╝╚═╝╚ ╩ ╚╩╝╩ ╩╩╚═╚═╝
let nativeQueryToFindTopTenMostVulnerableSoftwareItems ;
if ( sails . config . datastores . default . adapter === 'sails-postgresql' ) {
nativeQueryToFindTopTenMostVulnerableSoftwareItems = `
SELECT
vi . "softwareName" ,
vi . "versionName" ,
MIN ( vi . "fleetApid" ) AS "fleetApid" ,
COUNT ( DISTINCT v . id ) AS "numberOfVulns"
FROM vulnerabilityinstall vi
JOIN vulnerability v
ON vi . vulnerability = v . id
WHERE COALESCE ( vi . "uninstalledAt" , 0 ) = 0
GROUP BY
vi . "softwareName" ,
vi . "versionName"
ORDER BY
"numberOfVulns" DESC
LIMIT 10 ; ` ;
} else {
nativeQueryToFindTopTenMostVulnerableSoftwareItems = `
SELECT
vi . softwareName ,
vi . versionName ,
MIN ( vi . fleetApid ) AS fleetApid ,
COUNT ( DISTINCT v . id ) AS numberOfVulns
FROM vulnerabilityinstall vi
JOIN vulnerability v
ON vi . vulnerability = v . id
WHERE vi . uninstalledAt IS NULL OR vi . uninstalledAt = 0
GROUP BY
vi . softwareName ,
vi . versionName
ORDER BY
numberOfVulns DESC
LIMIT 10 ; ` ;
}
// console.time(`top ten most vulenerable software query`);
let topVulnerableSoftwareResult = await sails . sendNativeQuery ( nativeQueryToFindTopTenMostVulnerableSoftwareItems ) ;
// console.timeEnd(`top ten most vulenerable software query`);
let topTenMostVulnerableSoftwareItems = topVulnerableSoftwareResult . rows . map ( ( software ) => {
return {
softwareNameAndVersion : ` ${ software . softwareName } - ${ software . versionName } ` ,
fleetUrl : sails . config . custom . fleetBaseUrl + ` /software/versions/ ${ software . fleetApid } ` ,
numberOfVulns : software . numberOfVulns ,
} ;
} ) ;
dataForGraphs . mostVulnerableSoftware = topTenMostVulnerableSoftwareItems ;
// ╔═╗╦═╗╦╔╦╗╦╔═╗╔═╗╦ ╦ ╦ ╦ ╦═╗╔═╗╦═╗╔═╗ ╔═╗╔═╗╔═╗╔╦╗╦ ╦╔═╗╦═╗╔═╗
// ║ ╠╦╝║ ║ ║║ ╠═╣║ ║ ╚╦╝ ╠╦╝╠═╣╠╦╝║╣ ╚═╗║ ║╠╣ ║ ║║║╠═╣╠╦╝║╣
// ╚═╝╩╚═╩ ╩ ╩╚═╝╩ ╩╩═╝╩═╝╩ ╩╚═╩ ╩╩╚═╚═╝ ╚═╝╚═╝╚ ╩ ╚╩╝╩ ╩╩╚═╚═╝
// Software that is installed on <5 hosts with critical vulnerabilities.
let queryToFindTopUniqueCriticalSoftwareWithMostVulnerabilities ;
if ( sails . config . datastores . default . adapter === 'sails-postgresql' ) {
queryToFindTopUniqueCriticalSoftwareWithMostVulnerabilities = `
SELECT
vi . "softwareName" ,
STRING _AGG ( DISTINCT h . "displayName" , ', ' ORDER BY h . "displayName" ) AS "hostNames" ,
STRING _AGG ( DISTINCT v . "cveId" , ', ' ORDER BY v . "cveId" ) AS cves ,
STRING _AGG ( DISTINCT v . "cveDescription" , '; ' ORDER BY v . "cveDescription" ) AS descriptions ,
COUNT ( DISTINCT vi . host ) AS host _install _count
FROM vulnerabilityinstall vi
JOIN vulnerability v ON vi . vulnerability = v . id
JOIN host h ON vi . host = h . id
WHERE
( vi . "uninstalledAt" IS NULL OR vi . "uninstalledAt" = 0 )
AND v . severity >= 9.0
AND vi . "softwareName" ! ~ * '^(Python|perl|lib)'
GROUP BY
vi . "softwareName"
HAVING
COUNT ( DISTINCT vi . host ) < 3
ORDER BY
host _install _count ASC
LIMIT 10 ; ` ;
// queryToFindTopUniqueCriticalSoftwareWithMostVulnerabilities = `
// WITH "activeInstalls" AS (
// SELECT
// vulnerabilityinstall.host,
// vulnerabilityinstall."softwareName",
// vulnerabilityinstall."versionName",
// vulnerabilityinstall."fleetApid",
// vulnerabilityinstall."softwareName" AS "softwareNameAndVersion"
// FROM vulnerabilityinstall
// WHERE vulnerabilityinstall."uninstalledAt" IS NULL OR vulnerabilityinstall."uninstalledAt" = 0
// ),
// "softwareHostCounts" AS (
// SELECT
// "activeInstalls"."softwareNameAndVersion",
// COUNT(DISTINCT "activeInstalls".host) AS "hostInstallCount",
// STRING_AGG(DISTINCT host."displayName", ', ' ORDER BY host."displayName") AS "hostNames",
// STRING_AGG(
// DISTINCT "activeInstalls"."fleetApid"::text,
// ', ' ORDER BY "activeInstalls"."fleetApid"::text
// ) AS "fleetApid"
// FROM "activeInstalls"
// JOIN host ON host.id = "activeInstalls".host
// GROUP BY "activeInstalls"."softwareNameAndVersion"
// ),
// "criticalVulnerabilityAgg" AS (
// SELECT
// "activeInstalls"."softwareNameAndVersion",
// COUNT(DISTINCT vulnerability.id) AS "vulnerabilityCount",
// STRING_AGG(DISTINCT vulnerability."cveId", ', ' ORDER BY vulnerability."cveId") AS "cveIds"
// FROM "activeInstalls"
// JOIN vulnerabilityinstall ON
// vulnerabilityinstall.host = "activeInstalls".host
// AND vulnerabilityinstall."softwareName" = "activeInstalls"."softwareName"
// AND COALESCE(vulnerabilityinstall."versionName",'') = COALESCE("activeInstalls"."versionName",'')
// AND (vulnerabilityinstall."uninstalledAt" IS NULL OR vulnerabilityinstall."uninstalledAt" = 0)
// JOIN vulnerability ON vulnerability.id = vulnerabilityinstall.vulnerability
// WHERE vulnerability.severity >= 9.0
// GROUP BY "activeInstalls"."softwareNameAndVersion"
// )
// SELECT
// "softwareHostCounts"."softwareNameAndVersion",
// "softwareHostCounts"."hostInstallCount",
// "criticalVulnerabilityAgg"."vulnerabilityCount",
// "criticalVulnerabilityAgg"."cveIds",
// "softwareHostCounts"."hostNames",
// "softwareHostCounts"."fleetApid"
// FROM "softwareHostCounts"
// JOIN "criticalVulnerabilityAgg"
// ON "criticalVulnerabilityAgg"."softwareNameAndVersion" = "softwareHostCounts"."softwareNameAndVersion"
// WHERE "softwareHostCounts"."hostInstallCount" < 5
// ORDER BY
// "criticalVulnerabilityAgg"."vulnerabilityCount" DESC,
// "softwareHostCounts"."hostInstallCount" ASC,
// "softwareHostCounts"."softwareNameAndVersion" ASC
// LIMIT 10;`;
} else {
queryToFindTopUniqueCriticalSoftwareWithMostVulnerabilities = `
SELECT
vi . softwareName ,
2025-11-07 20:38:17 +00:00
GROUP _CONCAT ( DISTINCT h . displayName SEPARATOR ', ' ) AS hostNames ,
2025-11-07 18:01:57 +00:00
GROUP _CONCAT ( DISTINCT v . cveId SEPARATOR ', ' ) AS cves ,
GROUP _CONCAT ( DISTINCT v . cveDescription SEPARATOR '; ' ) AS descriptions ,
COUNT ( DISTINCT vi . host ) AS host _install _count
FROM
vulnerabilityinstall vi
JOIN
vulnerability v ON vi . vulnerability = v . id
JOIN
host h ON vi . host = h . id
WHERE
-- Consider only currently installed software
( vi . uninstalledAt IS NULL OR vi . uninstalledAt = 0 )
-- Filter for software associated with 'Critical' vulnerabilities ( CVSS 8.0 - 10.0 )
AND v . severity >= 8.0
-- Exclude software names starting with 'Python' or 'pert'
AND vi . softwareName NOT REGEXP '^(Python|perl|lib)'
GROUP BY
vi . softwareName
HAVING
host _install _count < 3
ORDER BY
-- Order by the number of hosts the software is installed on , ascending ,
-- to show the rarest software first .
host _install _count ASC
LIMIT 10 ` ;
// queryToFindTopUniqueCriticalSoftwareWithMostVulnerabilities = `
// WITH activeInstalls AS (
// SELECT
// vulnerabilityinstall.host,
// vulnerabilityinstall.softwareName,
// vulnerabilityinstall.versionName,
// vulnerabilityinstall.fleetApid,
// CONCAT(vulnerabilityinstall.softwareName AS softwareNameAndVersion
// FROM vulnerabilityinstall
// WHERE vulnerabilityinstall.uninstalledAt IS NULL OR vulnerabilityinstall.uninstalledAt = 0
// ),
// softwareHostCounts AS (
// SELECT
// activeInstalls.softwareNameAndVersion,
// COUNT(DISTINCT activeInstalls.host) AS hostInstallCount,
// GROUP_CONCAT(DISTINCT host.displayName ORDER BY host.displayName SEPARATOR ', ') AS hostNames,
// GROUP_CONCAT(DISTINCT CAST(activeInstalls.fleetApid AS CHAR) ORDER BY CAST(activeInstalls.fleetApid AS CHAR) SEPARATOR ', ') AS fleetApid
// FROM activeInstalls
// JOIN host ON host.id = activeInstalls.host
// GROUP BY activeInstalls.softwareNameAndVersion
// ),
// criticalVulnerabilityAgg AS (
// SELECT
// activeInstalls.softwareNameAndVersion,
// COUNT(DISTINCT vulnerability.id) AS vulnerabilityCount,
// GROUP_CONCAT(DISTINCT vulnerability.cveId ORDER BY vulnerability.cveId SEPARATOR ', ') AS cveIds
// FROM activeInstalls
// JOIN vulnerabilityinstall ON
// vulnerabilityinstall.host = activeInstalls.host
// AND vulnerabilityinstall.softwareName = activeInstalls.softwareName
// AND COALESCE(vulnerabilityinstall.versionName,'') = COALESCE(activeInstalls.versionName,'')
// AND (vulnerabilityinstall.uninstalledAt IS NULL OR vulnerabilityinstall.uninstalledAt = 0)
// JOIN vulnerability ON vulnerability.id = vulnerabilityinstall.vulnerability
// WHERE vulnerability.severity >= 9.0
// GROUP BY activeInstalls.softwareNameAndVersion
// )
// SELECT
// softwareHostCounts.softwareNameAndVersion,
// softwareHostCounts.hostInstallCount,
// criticalVulnerabilityAgg.vulnerabilityCount,
// criticalVulnerabilityAgg.cveIds,
// softwareHostCounts.hostNames,
// softwareHostCounts.fleetApid
// FROM softwareHostCounts
// JOIN criticalVulnerabilityAgg
// ON criticalVulnerabilityAgg.softwareNameAndVersion = softwareHostCounts.softwareNameAndVersion
// WHERE softwareHostCounts.hostInstallCount < 5
// ORDER BY
// criticalVulnerabilityAgg.vulnerabilityCount DESC,
// softwareHostCounts.hostInstallCount ASC,
// softwareHostCounts.softwareNameAndVersion ASC
// LIMIT 10;`;
}
// console.time('critical unique software query');
let topUniqueCriticalVulnsResult = await sails . sendNativeQuery ( queryToFindTopUniqueCriticalSoftwareWithMostVulnerabilities ) ;
// console.timeEnd('critical unique software query');
// console.log(topUniqueCriticalVulnsResult);
let uniqueCriticalSoftware = topUniqueCriticalVulnsResult . rows . map ( ( software ) => {
// Build an array of CVE objects, with each containing the CVE ID and a link to the Fleet page for the CVE.
let cves = software . cves . split ( ', ' ) . map ( ( cveId ) => {
return {
name : cveId ,
fleetUrl : ` ${ sails . config . custom . fleetBaseUrl } /software/vulnerabilities/ ${ cveId } `
} ;
} ) ;
return {
softwareNameAndVersion : software . softwareName ,
fleetUrl : ` ${ sails . config . custom . fleetBaseUrl } /software/versions/ ${ software . fleetApid } ` ,
numberOfVulns : cves . length ,
cves ,
affectedHosts : software . hostNames . split ( ', ' ) ,
} ;
} ) ;
dataForGraphs . uniqueCriticalSoftware = uniqueCriticalSoftware ;
// console.log(uniqueCriticalSoftware);
//
// ╦ ╦╔═╗╔═╗╔╦╗╔═╗ ╦ ╦╦╔╦╗╦ ╦ ╔╦╗╔═╗╔═╗╔╦╗ ╔═╗╦ ╦╔═╗╔═╗
// ╠═╣║ ║╚═╗ ║ ╚═╗ ║║║║ ║ ╠═╣ ║║║║ ║╚═╗ ║ ║ ╚╗╔╝║╣ ╚═╗
// ╩ ╩╚═╝╚═╝ ╩ ╚═╝ ╚╩╝╩ ╩ ╩ ╩ ╩ ╩╚═╝╚═╝ ╩ ╚═╝ ╚╝ ╚═╝╚═╝
let hostsWithMostVulnsQuery ;
if ( sails . config . datastores . default . adapter === 'sails-postgresql' ) {
hostsWithMostVulnsQuery = `
WITH "activeVulnerabilityInstalls" AS (
SELECT DISTINCT
vulnerabilityinstall . host ,
vulnerabilityinstall . vulnerability
FROM vulnerabilityinstall
WHERE
vulnerabilityinstall . "uninstalledAt" IS NULL
OR vulnerabilityinstall . "uninstalledAt" = 0
) ,
"vulnerabilityCountsByHost" AS (
SELECT
activeVulnerabilityInstalls . host ,
COUNT ( DISTINCT activeVulnerabilityInstalls . vulnerability ) AS "vulnerabilityCount" ,
STRING _AGG ( DISTINCT vulnerability . "cveId" , ', ' ORDER BY vulnerability . "cveId" ) AS "cveIds"
FROM "activeVulnerabilityInstalls" AS activeVulnerabilityInstalls
JOIN vulnerability
ON vulnerability . id = activeVulnerabilityInstalls . vulnerability
GROUP BY
activeVulnerabilityInstalls . host
)
SELECT
host . "displayName" AS "displayName" ,
host . "fleetApid" AS "fleetApid" ,
vulnerabilityCountsByHost . "vulnerabilityCount" ,
vulnerabilityCountsByHost . "cveIds"
FROM "vulnerabilityCountsByHost" AS vulnerabilityCountsByHost
JOIN host
ON host . id = vulnerabilityCountsByHost . host
ORDER BY
vulnerabilityCountsByHost . "vulnerabilityCount" DESC ,
host . "displayName" ASC
LIMIT 10 ; ` ;
} else {
hostsWithMostVulnsQuery = `
WITH activeVulnerabilityInstalls AS (
SELECT DISTINCT
vulnerabilityinstall . host ,
vulnerabilityinstall . vulnerability
FROM vulnerabilityinstall
WHERE
vulnerabilityinstall . uninstalledAt IS NULL
OR vulnerabilityinstall . uninstalledAt = 0
) ,
vulnerabilityCountsByHost AS (
SELECT
activeVulnerabilityInstalls . host ,
COUNT ( DISTINCT activeVulnerabilityInstalls . vulnerability ) AS vulnerabilityCount ,
GROUP _CONCAT (
DISTINCT vulnerability . cveId
ORDER BY vulnerability . cveId
SEPARATOR ', '
) AS cveIds
FROM activeVulnerabilityInstalls
JOIN vulnerability
ON vulnerability . id = activeVulnerabilityInstalls . vulnerability
GROUP BY activeVulnerabilityInstalls . host
)
SELECT
host . displayName AS displayName ,
host . fleetApid AS fleetApid ,
vulnerabilityCountsByHost . vulnerabilityCount ,
vulnerabilityCountsByHost . cveIds
FROM vulnerabilityCountsByHost
JOIN host
ON host . id = vulnerabilityCountsByHost . host
ORDER BY
vulnerabilityCountsByHost . vulnerabilityCount DESC ,
host . displayName ASC
LIMIT 10 ; ` ;
}
// console.time('hosts with most vulnerabilities query');
let hostWithMostVulnsResult = await sails . sendNativeQuery ( hostsWithMostVulnsQuery ) ;
// console.timeEnd('hosts with most vulnerabilities query');
let hostsWithMostVulns = hostWithMostVulnsResult . rows . map ( ( host ) => {
let cves = host . cveIds . split ( ', ' ) . map ( ( cveId ) => {
return {
name : cveId ,
fleetUrl : ` ${ sails . config . custom . fleetBaseUrl } /software/vulnerabilities/ ${ cveId } `
} ;
} ) ;
return {
displayName : host . displayName ,
fleetUrl : ` ${ sails . config . custom . fleetBaseUrl } /hosts/ ${ host . fleetApid } ` ,
numberOfVulns : host . vulnerabilityCount ,
cves ,
} ;
} ) ;
dataForGraphs . hostsWithMostVulns = hostsWithMostVulns ;
//
// ╔═╗╦ ╦╔═╗ ╔═╗╔═╗╔╦╗╦╦ ╦╦╔╦╗╦ ╦ ╔╦╗╦═╗╔═╗╔╗╔╔╦╗╔═╗
// ║ ╚╗╔╝║╣ ╠═╣║ ║ ║╚╗╔╝║ ║ ╚╦╝ ║ ╠╦╝║╣ ║║║ ║║╚═╗
// ╚═╝ ╚╝ ╚═╝ ╩ ╩╚═╝ ╩ ╩ ╚╝ ╩ ╩ ╩ ╩ ╩╚═╚═╝╝╚╝═╩╝╚═╝
let queryToFindRemediationVeloticy ;
if ( sails . config . datastores . default . adapter === 'sails-postgresql' ) {
queryToFindRemediationVeloticy = `
WITH "params" AS (
SELECT
( 3 : : bigint * 24 * 60 * 60 * 1000 ) AS "graceMs"
) ,
"monthAnchors" AS (
SELECT date _trunc ( 'month' , ( now ( ) AT TIME ZONE 'UTC' ) ) : : timestamptz AS "thisMonthStartTs"
) ,
"monthBoundaries" AS (
SELECT
gs AS "monthStartTs" ,
LEAD ( gs ) OVER ( ORDER BY gs ) AS "monthEndTs"
FROM generate _series (
( SELECT "thisMonthStartTs" - INTERVAL '4 months' FROM "monthAnchors" ) ,
( SELECT "thisMonthStartTs" FROM "monthAnchors" ) ,
INTERVAL '1 month'
) AS gs
) ,
"months" AS (
SELECT
( EXTRACT ( EPOCH FROM "monthStartTs" ) * 1000 ) : : bigint AS "monthStartMs" ,
( EXTRACT ( EPOCH FROM "monthEndTs" ) * 1000 ) : : bigint AS "monthEndMs"
FROM "monthBoundaries"
WHERE "monthEndTs" IS NOT NULL
) ,
"rowsWithLag" AS (
SELECT
vulnerabilityinstall . host ,
vulnerabilityinstall . "softwareName" ,
vulnerabilityinstall . "versionName" ,
vulnerabilityinstall . vulnerability ,
vulnerabilityinstall . "createdAt" : : bigint AS "createdAtMs" ,
vulnerabilityinstall . "uninstalledAt" : : bigint AS "uninstalledAtMs" ,
LAG ( vulnerabilityinstall . "uninstalledAt" : : bigint ) OVER (
PARTITION BY
vulnerabilityinstall . host ,
vulnerabilityinstall . "softwareName" ,
vulnerabilityinstall . "versionName" ,
vulnerabilityinstall . vulnerability
ORDER BY vulnerabilityinstall . "createdAt" : : bigint
) AS "prevUninstalledMs"
FROM vulnerabilityinstall
) ,
"labeledEpisodes" AS (
SELECT
"rowsWithLag" . * ,
CASE
WHEN "rowsWithLag" . "prevUninstalledMs" IS NULL THEN 1
WHEN "rowsWithLag" . "createdAtMs" > "rowsWithLag" . "prevUninstalledMs" + ( SELECT "graceMs" FROM "params" ) THEN 1
ELSE 0
END AS "isNewEpisode"
FROM "rowsWithLag"
) ,
"episodeIndex" AS (
SELECT
host ,
"softwareName" ,
"versionName" ,
vulnerability ,
"createdAtMs" ,
"uninstalledAtMs" ,
SUM ( "isNewEpisode" ) OVER (
PARTITION BY host , "softwareName" , "versionName" , vulnerability
ORDER BY "createdAtMs"
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS "episodeId"
FROM "labeledEpisodes"
) ,
"episodes" AS (
SELECT
host ,
"softwareName" ,
"versionName" ,
vulnerability ,
MIN ( "createdAtMs" ) AS "episodeStartMs" ,
NULLIF ( MAX ( COALESCE ( "uninstalledAtMs" , 0 ) ) , 0 ) AS "episodeEndMs"
FROM "episodeIndex"
GROUP BY host , "softwareName" , "versionName" , vulnerability , "episodeId"
) ,
"newCvesByMonth" AS (
SELECT
"months" . "monthStartMs" ,
COUNT ( * ) AS "newCves"
FROM "months"
JOIN "episodes"
ON "episodes" . "episodeStartMs" >= "months" . "monthStartMs"
AND "episodes" . "episodeStartMs" < "months" . "monthEndMs"
GROUP BY "months" . "monthStartMs"
) ,
"remediatedCvesByMonth" AS (
SELECT
"months" . "monthStartMs" ,
COUNT ( * ) AS "remediatedCves"
FROM "months"
JOIN "episodes"
ON "episodes" . "episodeEndMs" IS NOT NULL
AND "episodes" . "episodeEndMs" >= "months" . "monthStartMs"
AND "episodes" . "episodeEndMs" < "months" . "monthEndMs"
GROUP BY "months" . "monthStartMs"
) ,
"activeCveCountByMonth" AS (
SELECT
"months" . "monthStartMs" ,
COUNT ( * ) AS "activeCveCount"
FROM "months"
JOIN "episodes"
ON "episodes" . "episodeStartMs" < "months" . "monthEndMs"
AND (
"episodes" . "episodeEndMs" IS NULL
OR "episodes" . "episodeEndMs" >= "months" . "monthEndMs"
)
GROUP BY "months" . "monthStartMs"
)
SELECT
"months" . "monthStartMs" ,
COALESCE ( "newCvesByMonth" . "newCves" , 0 ) AS "newCves" ,
COALESCE ( "remediatedCvesByMonth" . "remediatedCves" , 0 ) AS "remediatedCves" ,
COALESCE ( "activeCveCountByMonth" . "activeCveCount" , 0 ) AS "activeCveCount"
FROM "months"
LEFT JOIN "newCvesByMonth"
ON "newCvesByMonth" . "monthStartMs" = "months" . "monthStartMs"
LEFT JOIN "remediatedCvesByMonth"
ON "remediatedCvesByMonth" . "monthStartMs" = "months" . "monthStartMs"
LEFT JOIN "activeCveCountByMonth"
ON "activeCveCountByMonth" . "monthStartMs" = "months" . "monthStartMs"
ORDER BY "months" . "monthStartMs" ASC ; ` ;
} else {
queryToFindRemediationVeloticy = `
WITH
params AS (
SELECT CAST ( 3 * 24 * 60 * 60 * 1000 AS SIGNED ) AS graceMs
) ,
monthAnchors AS (
SELECT TIMESTAMP ( DATE _FORMAT ( UTC _TIMESTAMP ( ) , '%Y-%m-01 00:00:00' ) ) AS thisMonthStartTs
) ,
monthBoundaries AS (
WITH RECURSIVE m AS (
SELECT
0 AS n ,
DATE _SUB ( ( SELECT thisMonthStartTs FROM monthAnchors ) , INTERVAL 4 MONTH ) AS monthStartTs
UNION ALL
SELECT
n + 1 ,
DATE _ADD ( monthStartTs , INTERVAL 1 MONTH )
FROM m
WHERE n < 3
)
SELECT monthStartTs FROM m
) ,
months AS (
SELECT
CAST ( UNIX _TIMESTAMP ( monthStartTs ) * 1000 AS SIGNED ) AS monthStartMs ,
CAST ( UNIX _TIMESTAMP ( DATE _ADD ( monthStartTs , INTERVAL 1 MONTH ) ) * 1000 AS SIGNED ) AS monthEndMs
FROM monthBoundaries
) ,
rowsWithLag AS (
SELECT
vulnerabilityinstall . host ,
vulnerabilityinstall . softwareName ,
vulnerabilityinstall . versionName ,
vulnerabilityinstall . vulnerability ,
CAST ( vulnerabilityinstall . createdAt AS SIGNED ) AS createdAtMs ,
CAST ( vulnerabilityinstall . uninstalledAt AS SIGNED ) AS uninstalledAtMs ,
LAG ( CAST ( vulnerabilityinstall . uninstalledAt AS SIGNED ) ) OVER (
PARTITION BY
vulnerabilityinstall . host ,
vulnerabilityinstall . softwareName ,
vulnerabilityinstall . versionName ,
vulnerabilityinstall . vulnerability
ORDER BY CAST ( vulnerabilityinstall . createdAt AS SIGNED )
) AS prevUninstalledMs
FROM vulnerabilityinstall
) ,
labeledEpisodes AS (
SELECT
rowsWithLag . * ,
CASE
WHEN rowsWithLag . prevUninstalledMs IS NULL THEN 1
WHEN rowsWithLag . createdAtMs > rowsWithLag . prevUninstalledMs + ( SELECT graceMs FROM params ) THEN 1
ELSE 0
END AS isNewEpisode
FROM rowsWithLag
) ,
episodeIndex AS (
SELECT
host ,
softwareName ,
versionName ,
vulnerability ,
createdAtMs ,
uninstalledAtMs ,
SUM ( isNewEpisode ) OVER (
PARTITION BY host , softwareName , versionName , vulnerability
ORDER BY createdAtMs
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS episodeId
FROM labeledEpisodes
) ,
episodes AS (
SELECT
host ,
softwareName ,
versionName ,
vulnerability ,
MIN ( createdAtMs ) AS episodeStartMs ,
NULLIF ( MAX ( COALESCE ( uninstalledAtMs , 0 ) ) , 0 ) AS episodeEndMs
FROM episodeIndex
GROUP BY host , softwareName , versionName , vulnerability , episodeId
) ,
newCvesByMonth AS (
SELECT
months . monthStartMs ,
COUNT ( * ) AS newCves
FROM months
JOIN episodes
ON episodes . episodeStartMs >= months . monthStartMs
AND episodes . episodeStartMs < months . monthEndMs
GROUP BY months . monthStartMs
) ,
remediatedCvesByMonth AS (
SELECT
months . monthStartMs ,
COUNT ( * ) AS remediatedCves
FROM months
JOIN episodes
ON episodes . episodeEndMs IS NOT NULL
AND episodes . episodeEndMs >= months . monthStartMs
AND episodes . episodeEndMs < months . monthEndMs
GROUP BY months . monthStartMs
) ,
activeCveCountByMonth AS (
SELECT
months . monthStartMs ,
COUNT ( * ) AS activeCveCount
FROM months
JOIN episodes
ON episodes . episodeStartMs < months . monthEndMs
AND ( episodes . episodeEndMs IS NULL OR episodes . episodeEndMs >= months . monthEndMs )
GROUP BY months . monthStartMs
)
SELECT
months . monthStartMs ,
COALESCE ( newCvesByMonth . newCves , 0 ) AS newCves ,
COALESCE ( remediatedCvesByMonth . remediatedCves , 0 ) AS remediatedCves ,
COALESCE ( activeCveCountByMonth . activeCveCount , 0 ) AS activeCveCount
FROM months
LEFT JOIN newCvesByMonth
ON newCvesByMonth . monthStartMs = months . monthStartMs
LEFT JOIN remediatedCvesByMonth
ON remediatedCvesByMonth . monthStartMs = months . monthStartMs
LEFT JOIN activeCveCountByMonth
ON activeCveCountByMonth . monthStartMs = months . monthStartMs
ORDER BY months . monthStartMs ASC ; ` ;
}
// console.time('remediation velocity query');
let remediationTrendResult = await sails . sendNativeQuery ( queryToFindRemediationVeloticy ) ;
// console.timeEnd('remediation velocity query');
let activityTrendsTimeline = remediationTrendResult . rows . map ( ( month ) => {
return {
monthStartedAt : month . monthStartMs ,
timelineLabel : new Date ( Number ( month . monthStartMs ) ) . toLocaleString ( 'en-US' , { month : 'short' , year : 'numeric' } ) ,
newCves : month . newCves ,
remediatedCves : month . remediatedCves ,
totalNumberOfCves : month . activeCveCount ,
} ;
} ) ;
dataForGraphs . activityTrendsTimeline = activityTrendsTimeline ;
//
// ╔═╗╦ ╦╔═╗ ╦═╗╔═╗╔╦╗╔═╗╔╦╗╦╔═╗╔╦╗╦╔═╗╔╗╔ ╔═╗╦ ╦╔╦╗╔╦╗╔═╗╦═╗╦ ╦
// ║ ╚╗╔╝║╣ ╠╦╝║╣ ║║║║╣ ║║║╠═╣ ║ ║║ ║║║║ ╚═╗║ ║║║║║║║╠═╣╠╦╝╚╦╝
// ╚═╝ ╚╝ ╚═╝ ╩╚═╚═╝╩ ╩╚═╝═╩╝╩╩ ╩ ╩ ╩╚═╝╝╚╝ ╚═╝╚═╝╩ ╩╩ ╩╩ ╩╩╚═ ╩
let thirtyDaysInMs = ( 1000 * 60 * 60 * 24 * 30 ) ;
let ninetyDaysInMs = ( 1000 * 60 * 60 * 24 * 90 ) ;
let thirtyDaysAgoAt = Date . now ( ) - thirtyDaysInMs ;
let ninetyDaysAgoAt = Date . now ( ) - ninetyDaysInMs ;
// let numberOfNewCvesInThePastWeek = await Vulnerability.count({createdAt: {'>': oneWeekAgoAt}});
// console.log('numberOfNewCvesInThePastWeek:', numberOfNewCvesInThePastWeek);
let numberOfNewAndActiveVulnInstallsInThePastThirtyDays = await VulnerabilityInstall . count ( { installedAt : { '>' : thirtyDaysAgoAt } , uninstalledAt : 0 } ) ;
// console.log('numberOfNewAndActiveVulnInstallsInThePastWeek:', numberOfNewAndActiveVulnInstallsInThePastWeek);
// let numberOfNewCvesInThePastThirtyDays = await Vulnerability.count({createdAt: {'>': thirtyDaysAgoAt}});
let numberOfNewAndActiveVulnInstallsInThePastNinetyDays = await VulnerabilityInstall . count ( { installedAt : { '>' : ninetyDaysAgoAt } , uninstalledAt : 0 } ) ;
// console.log('numberOfNewCvesInThePastThirtyDays:', numberOfNewCvesInThePastThirtyDays):
// console.log('numberOfNewAndActiveVulnInstallsInThePastThirtyDays:', numberOfNewAndActiveVulnInstallsInThePastThirtyDays);
let remediationSummary = {
newCvesThirtyDays : numberOfNewAndActiveVulnInstallsInThePastThirtyDays ,
newCvesNinetyDays : numberOfNewAndActiveVulnInstallsInThePastNinetyDays ,
} ;
// Send native queries to get number of remediated CVEs
let nativeQueryToGetNumberOfRemediatedCves ;
if ( sails . config . datastores . default . adapter === 'sails-postgresql' ) {
nativeQueryToGetNumberOfRemediatedCves = `
WITH "timeBounds" AS (
SELECT
( EXTRACT ( EPOCH FROM ( now ( ) AT TIME ZONE 'UTC' ) ) * 1000 ) : : bigint AS "nowMs" ,
( EXTRACT ( EPOCH FROM ( ( now ( ) AT TIME ZONE 'UTC' ) - INTERVAL '30 days' ) ) * 1000 ) : : bigint AS "thirtyDaysAgoMs" ,
( EXTRACT ( EPOCH FROM ( ( now ( ) AT TIME ZONE 'UTC' ) - INTERVAL '90 days' ) ) * 1000 ) : : bigint AS "ninetyDaysAgoMs"
) ,
"remediatedOnceLast90Days" AS (
SELECT
vulnerabilityinstall . id ,
vulnerabilityinstall . "uninstalledAt" AS "remediatedAtMs"
FROM vulnerabilityinstall
JOIN "timeBounds" ON TRUE
WHERE
vulnerabilityinstall . "uninstalledAt" IS NOT NULL
AND vulnerabilityinstall . "uninstalledAt" > 0
AND vulnerabilityinstall . "uninstalledAt" >= "timeBounds" . "ninetyDaysAgoMs"
AND vulnerabilityinstall . "uninstalledAt" < "timeBounds" . "nowMs"
AND NOT EXISTS (
SELECT 1
FROM vulnerabilityinstall AS vi _reinstall
WHERE
vi _reinstall . host = vulnerabilityinstall . host
AND vi _reinstall . vulnerability = vulnerabilityinstall . vulnerability
AND vi _reinstall . "softwareName" = vulnerabilityinstall . "softwareName"
AND COALESCE ( vi _reinstall . "versionName" , '' ) = COALESCE ( vulnerabilityinstall . "versionName" , '' )
AND vi _reinstall . "createdAt" > vulnerabilityinstall . "uninstalledAt"
)
)
SELECT
COUNT ( * ) FILTER ( WHERE "remediatedAtMs" >= "timeBounds" . "thirtyDaysAgoMs" ) AS "remediatedCveCountLast30Days" ,
COUNT ( * ) AS "remediatedCveCountLast90Days"
FROM "remediatedOnceLast90Days"
CROSS JOIN "timeBounds" ; ` ;
} else {
nativeQueryToGetNumberOfRemediatedCves = `
WITH timeBounds AS (
SELECT
CAST ( UNIX _TIMESTAMP ( UTC _TIMESTAMP ( ) ) * 1000 AS SIGNED ) AS nowMs ,
CAST ( UNIX _TIMESTAMP ( DATE _SUB ( UTC _TIMESTAMP ( ) , INTERVAL 7 DAY ) ) * 1000 AS SIGNED ) AS thirtyDaysAgoMs ,
CAST ( UNIX _TIMESTAMP ( DATE _SUB ( UTC _TIMESTAMP ( ) , INTERVAL 30 DAY ) ) * 1000 AS SIGNED ) AS ninetyDaysAgoMs
) ,
remediatedOnceLast90Days AS (
SELECT
vulnerabilityinstall . id ,
vulnerabilityinstall . uninstalledAt AS remediatedAtMs
FROM vulnerabilityinstall
JOIN timeBounds ON TRUE
WHERE
vulnerabilityinstall . uninstalledAt IS NOT NULL
AND vulnerabilityinstall . uninstalledAt > 0
AND vulnerabilityinstall . uninstalledAt >= timeBounds . ninetyDaysAgoMs
AND vulnerabilityinstall . uninstalledAt < timeBounds . nowMs
AND NOT EXISTS (
SELECT 1
FROM vulnerabilityinstall AS vi _reinstall
WHERE
vi _reinstall . host = vulnerabilityinstall . host
AND vi _reinstall . vulnerability = vulnerabilityinstall . vulnerability
AND vi _reinstall . softwareName = vulnerabilityinstall . softwareName
AND COALESCE ( vi _reinstall . versionName , '' ) = COALESCE ( vulnerabilityinstall . versionName , '' )
AND vi _reinstall . createdAt > vulnerabilityinstall . uninstalledAt
)
)
SELECT
SUM ( CASE WHEN remediatedAtMs >= timeBounds . thirtyDaysAgoMs THEN 1 ELSE 0 END ) AS remediatedCveCountLast30Days ,
COUNT ( * ) AS remediatedCveCountLast90Days
FROM remediatedOnceLast90Days
CROSS JOIN timeBounds ; ` ;
}
// console.time('recent remediated cves query');
let remediatedCvesQueryResult = await sails . sendNativeQuery ( nativeQueryToGetNumberOfRemediatedCves ) ;
// console.timeEnd('recent remediated cves query');
remediationSummary . remediatedCvesThirtyDays = remediatedCvesQueryResult . rows [ 0 ] . remediatedCveCountLast30Days ? remediatedCvesQueryResult . rows [ 0 ] . remediatedCveCountLast30Days : 0 ;
remediationSummary . remediatedCvesNinetyDays = remediatedCvesQueryResult . rows [ 0 ] . remediatedCveCountLast90Days ? remediatedCvesQueryResult . rows [ 0 ] . remediatedCveCountLast90Days : 0 ;
dataForGraphs . remediationSummary = remediationSummary ;
//
// ╔═╗╦ ╔╦╗╔═╗╔═╗╔╦╗ ╔═╗╦ ╦╔═╗╔═╗ ╦ ╦╦╔╦╗╦ ╦ ╔═╗═╗ ╦╔═╗╦ ╔═╗╦╔╦╗╔═╗
// ║ ║║ ║║║╣ ╚═╗ ║ ║ ╚╗╔╝║╣ ╚═╗ ║║║║ ║ ╠═╣ ║╣ ╔╩╦╝╠═╝║ ║ ║║ ║ ╚═╗
// ╚═╝╩═╝═╩╝╚═╝╚═╝ ╩ ╚═╝ ╚╝ ╚═╝╚═╝ ╚╩╝╩ ╩ ╩ ╩ ╚═╝╩ ╚═╩ ╩═╝╚═╝╩ ╩ ╚═╝
let queryToFindOldestExploitableCves ;
if ( sails . config . datastores . default . adapter === 'sails-postgresql' ) {
queryToFindOldestExploitableCves = `
WITH oldestExploitable AS (
SELECT DISTINCT vulnerability . "cveId" , vulnerability . "publishedAt"
FROM vulnerability
JOIN vulnerabilityinstall
ON vulnerabilityinstall . vulnerability = vulnerability . id
AND ( vulnerabilityinstall . "uninstalledAt" IS NULL OR vulnerabilityinstall . "uninstalledAt" = 0 )
WHERE vulnerability . "hasKnownExploit" = TRUE
)
SELECT "cveId"
FROM oldestExploitable
ORDER BY "publishedAt" ASC
LIMIT 5 ; ` ;
} else {
queryToFindOldestExploitableCves = `
WITH oldestExploitable AS (
SELECT DISTINCT
vulnerability . cveId ,
vulnerability . publishedAt
FROM vulnerability
JOIN vulnerabilityinstall
ON vulnerabilityinstall . vulnerability = vulnerability . id
AND ( vulnerabilityinstall . uninstalledAt IS NULL
OR vulnerabilityinstall . uninstalledAt = 0 )
WHERE vulnerability . hasKnownExploit = TRUE
)
SELECT cveId
FROM oldestExploitable
ORDER BY publishedAt ASC
LIMIT 5 ; ` ;
}
// console.time('oldest exploitable cves query');
let oldestExploitableCvesResult = await sails . sendNativeQuery ( queryToFindOldestExploitableCves ) ;
// console.timeEnd('oldest exploitable cves query');
let oldestExploitableCves = oldestExploitableCvesResult . rows . map ( ( cve ) => {
return {
cveId : cve . cveId ,
fleetUrl : ` ${ sails . config . custom . fleetBaseUrl } /software/vulnerabilities/ ${ cve . cveId } ` ,
yearPublished : cve . cveId . split ( '-' ) [ 1 ] ,
} ;
} ) ;
dataForGraphs . oldestExploitableCves = oldestExploitableCves ;
//
// ╦ ╦╔═╗╔═╗╔╦╗╔═╗ ╦ ╦╦╔╦╗╦ ╦ ╔═╗╦ ╔╦╗╔═╗╔═╗╔╦╗ ╔═╗═╗ ╦╔═╗╦ ╔═╗╦╔╦╗╔═╗╔╗ ╦ ╔═╗ ╔═╗╦ ╦╔═╗╔═╗
// ╠═╣║ ║╚═╗ ║ ╚═╗ ║║║║ ║ ╠═╣ ║ ║║ ║║║╣ ╚═╗ ║ ║╣ ╔╩╦╝╠═╝║ ║ ║║ ║ ╠═╣╠╩╗║ ║╣ ║ ╚╗╔╝║╣ ╚═╗
// ╩ ╩╚═╝╚═╝ ╩ ╚═╝ ╚╩╝╩ ╩ ╩ ╩ ╚═╝╩═╝═╩╝╚═╝╚═╝ ╩ ╚═╝╩ ╚═╩ ╩═╝╚═╝╩ ╩ ╩ ╩╚═╝╩═╝╚═╝ ╚═╝ ╚╝ ╚═╝╚═╝
let queryToFindHostsWithOldestExploitableCves ;
if ( sails . config . datastores . default . adapter === 'sails-postgresql' ) {
queryToFindHostsWithOldestExploitableCves = `
WITH "hostOldestExploitable" AS (
SELECT
host . id AS "hostId" ,
host . "displayName" AS "displayName" ,
host . "fleetApid" AS "fleetApid" ,
vulnerability . "cveId" AS "cveId" ,
vulnerability . "publishedAt" AS "publishedAtMs" ,
vulnerabilityinstall . "softwareName" AS "softwareName" ,
vulnerabilityinstall . "versionName" AS "versionName"
FROM vulnerabilityinstall
JOIN vulnerability
ON vulnerability . id = vulnerabilityinstall . vulnerability
AND vulnerability . "hasKnownExploit" = TRUE
JOIN host
ON host . id = vulnerabilityinstall . host
WHERE
vulnerabilityinstall . "uninstalledAt" IS NULL
OR vulnerabilityinstall . "uninstalledAt" = 0
) ,
"rankedOldestPerHost" AS (
SELECT
"hostId" ,
"displayName" ,
"fleetApid" ,
"cveId" ,
"publishedAtMs" ,
"softwareName" ,
"versionName" ,
ROW _NUMBER ( ) OVER (
PARTITION BY "hostId"
ORDER BY "publishedAtMs" ASC
) AS "rowNumber"
FROM "hostOldestExploitable"
)
SELECT
"displayName" ,
"fleetApid" ,
"cveId" ,
( "softwareName" || ' ' || COALESCE ( "versionName" , '' ) ) AS "softwareNameAndVersion" ,
"publishedAtMs"
FROM "rankedOldestPerHost"
WHERE "rowNumber" = 1
ORDER BY "publishedAtMs" ASC
LIMIT 5 ; ` ;
} else {
queryToFindHostsWithOldestExploitableCves = `
WITH hostOldestExploitable AS (
SELECT
host . id AS hostId ,
host . displayName AS displayName ,
host . fleetApid AS fleetApid ,
vulnerability . cveId AS cveId ,
vulnerability . publishedAt AS publishedAtMs ,
vulnerabilityinstall . softwareName AS softwareName ,
vulnerabilityinstall . versionName AS versionName
FROM vulnerabilityinstall
JOIN vulnerability
ON vulnerability . id = vulnerabilityinstall . vulnerability
AND vulnerability . hasKnownExploit = TRUE
JOIN host
ON host . id = vulnerabilityinstall . host
WHERE
vulnerabilityinstall . uninstalledAt IS NULL
OR vulnerabilityinstall . uninstalledAt = 0
) ,
rankedOldestPerHost AS (
SELECT
hostId ,
displayName ,
fleetApid ,
cveId ,
publishedAtMs ,
softwareName ,
versionName ,
ROW _NUMBER ( ) OVER (
PARTITION BY hostId
ORDER BY publishedAtMs ASC
) AS rowNumber
FROM hostOldestExploitable
)
SELECT
displayName ,
fleetApid ,
cveId ,
CONCAT ( softwareName , ' ' , COALESCE ( versionName , '' ) ) AS softwareNameAndVersion ,
publishedAtMs
FROM rankedOldestPerHost
WHERE rowNumber = 1
ORDER BY publishedAtMs ASC
LIMIT 5 ; ` ;
}
// console.time('oldest exploitable hosts query');
let oldestExploitableHostsResult = await sails . sendNativeQuery ( queryToFindHostsWithOldestExploitableCves ) ;
// console.timeEnd('oldest exploitable hosts query');
let oldestExploitableHosts = oldestExploitableHostsResult . rows . map ( ( host ) => {
return {
displayName : host . displayName ,
affectedSoftware : host . softwareNameAndVersion ,
fleetUrl : ` ${ sails . config . custom . fleetBaseUrl } /hosts/ ${ host . fleetApid } ` ,
cveId : host . cveId ,
yearPublished : host . cveId . split ( '-' ) [ 1 ] ,
} ;
} ) ;
dataForGraphs . oldestExploitableHosts = oldestExploitableHosts ;
//
// ╔╗╔╔═╗╦ ╦╔═╗╔═╗╔╦╗ ╔═╗╦ ╦╔═╗╔═╗ ╦ ╦╦╔╦╗╦ ╦ ╔═╗═╗ ╦╔═╗╦ ╔═╗╦╔╦╗╔═╗
// ║║║║╣ ║║║║╣ ╚═╗ ║ ║ ╚╗╔╝║╣ ╚═╗ ║║║║ ║ ╠═╣ ║╣ ╔╩╦╝╠═╝║ ║ ║║ ║ ╚═╗
// ╝╚╝╚═╝╚╩╝╚═╝╚═╝ ╩ ╚═╝ ╚╝ ╚═╝╚═╝ ╚╩╝╩ ╩ ╩ ╩ ╚═╝╩ ╚═╩ ╩═╝╚═╝╩ ╩ ╚═╝
let queryToFindNewestExploitableCves ;
if ( sails . config . datastores . default . adapter === 'sails-postgresql' ) {
queryToFindNewestExploitableCves = `
WITH newestExploitable AS (
SELECT DISTINCT vulnerability . "cveId" , vulnerability . "publishedAt"
FROM vulnerability
JOIN vulnerabilityinstall
ON vulnerabilityinstall . vulnerability = vulnerability . id
AND ( vulnerabilityinstall . "uninstalledAt" IS NULL OR vulnerabilityinstall . "uninstalledAt" = 0 )
WHERE vulnerability . "hasKnownExploit" = TRUE
)
SELECT "cveId"
FROM newestExploitable
ORDER BY "publishedAt" DESC
LIMIT 5 ; ` ;
} else {
queryToFindNewestExploitableCves = `
WITH newestExploitable AS (
SELECT DISTINCT
vulnerability . cveId ,
vulnerability . publishedAt
FROM vulnerability
JOIN vulnerabilityinstall
ON vulnerabilityinstall . vulnerability = vulnerability . id
AND ( vulnerabilityinstall . uninstalledAt IS NULL OR vulnerabilityinstall . uninstalledAt = 0 )
WHERE vulnerability . hasKnownExploit = TRUE
)
SELECT cveId
FROM newestExploitable
ORDER BY publishedAt DESC
LIMIT 5 ; ` ;
}
// console.time('newest exploitable cves');
let newestExploitableCvesResult = await sails . sendNativeQuery ( queryToFindNewestExploitableCves ) ;
// console.timeEnd('newest exploitable cves');
// console.log(newestExploitableCvesResult);
let newestExploitableCves = newestExploitableCvesResult . rows . map ( ( cve ) => {
return {
cveId : cve . cveId ,
fleetUrl : ` ${ sails . config . custom . fleetBaseUrl } /software/vulnerabilities/ ${ cve . cveId } ` ,
yearPublished : cve . cveId . split ( '-' ) [ 1 ] ,
} ;
} ) ;
dataForGraphs . newestExploitableCves = newestExploitableCves ;
//
// ╦ ╦╔═╗╔═╗╔╦╗╔═╗ ╦ ╦╦╔╦╗╦ ╦ ╔╗╔╔═╗╦ ╦╔═╗╔═╗╔╦╗ ╔═╗═╗ ╦╔═╗╦ ╔═╗╦╔╦╗╔═╗╔╗ ╦ ╔═╗ ╔═╗╦ ╦╔═╗╔═╗
// ╠═╣║ ║╚═╗ ║ ╚═╗ ║║║║ ║ ╠═╣ ║║║║╣ ║║║║╣ ╚═╗ ║ ║╣ ╔╩╦╝╠═╝║ ║ ║║ ║ ╠═╣╠╩╗║ ║╣ ║ ╚╗╔╝║╣ ╚═╗
// ╩ ╩╚═╝╚═╝ ╩ ╚═╝ ╚╩╝╩ ╩ ╩ ╩ ╝╚╝╚═╝╚╩╝╚═╝╚═╝ ╩ ╚═╝╩ ╚═╩ ╩═╝╚═╝╩ ╩ ╩ ╩╚═╝╩═╝╚═╝ ╚═╝ ╚╝ ╚═╝╚═╝
let queryToFindHostsWithNewestExploitableCves ;
if ( sails . config . datastores . default . adapter === 'sails-postgresql' ) {
queryToFindHostsWithNewestExploitableCves = `
WITH "hostNewestExploitable" AS (
SELECT
host . id AS "hostId" ,
host . "displayName" AS "displayName" ,
host . "fleetApid" AS "fleetApid" ,
vulnerability . "cveId" AS "cveId" ,
vulnerability . "publishedAt" AS "publishedAtMs" ,
vulnerabilityinstall . "softwareName" AS "softwareName" ,
vulnerabilityinstall . "versionName" AS "versionName"
FROM vulnerabilityinstall
JOIN vulnerability
ON vulnerability . id = vulnerabilityinstall . vulnerability
AND vulnerability . "hasKnownExploit" = TRUE
JOIN host
ON host . id = vulnerabilityinstall . host
WHERE
vulnerabilityinstall . "uninstalledAt" IS NULL
OR vulnerabilityinstall . "uninstalledAt" = 0
) ,
"rankedNewestPerHost" AS (
SELECT
"hostId" ,
"displayName" ,
"fleetApid" ,
"cveId" ,
"publishedAtMs" ,
"softwareName" ,
"versionName" ,
ROW _NUMBER ( ) OVER (
PARTITION BY "hostId"
ORDER BY "publishedAtMs" ASC
) AS "rowNumber"
FROM "hostNewestExploitable"
)
SELECT
"displayName" ,
"fleetApid" ,
"cveId" ,
( "softwareName" || ' ' || COALESCE ( "versionName" , '' ) ) AS "softwareNameAndVersion" ,
"publishedAtMs"
FROM "rankedNewestPerHost"
WHERE "rowNumber" = 1
ORDER BY "publishedAtMs" DESC
LIMIT 5 ; ` ;
} else {
queryToFindHostsWithNewestExploitableCves = `
WITH hostNewestExploitable AS (
SELECT
host . id AS hostId ,
host . displayName AS displayName ,
host . fleetApid AS fleetApid ,
vulnerability . cveId AS cveId ,
vulnerability . publishedAt AS publishedAtMs ,
vulnerabilityinstall . softwareName AS softwareName ,
vulnerabilityinstall . versionName AS versionName
FROM vulnerabilityinstall
JOIN vulnerability
ON vulnerability . id = vulnerabilityinstall . vulnerability
AND vulnerability . hasKnownExploit = TRUE
JOIN host
ON host . id = vulnerabilityinstall . host
WHERE
vulnerabilityinstall . uninstalledAt IS NULL
OR vulnerabilityinstall . uninstalledAt = 0
) ,
rankedNewestPerHost AS (
SELECT
hostId ,
displayName ,
fleetApid ,
cveId ,
publishedAtMs ,
softwareName ,
versionName ,
ROW _NUMBER ( ) OVER (
PARTITION BY hostId
ORDER BY publishedAtMs ASC
) AS rowNumber
FROM hostNewestExploitable
)
SELECT
displayName ,
fleetApid ,
cveId ,
CONCAT ( softwareName , ' ' , COALESCE ( versionName , '' ) ) AS softwareNameAndVersion ,
publishedAtMs
FROM rankedNewestPerHost
WHERE rowNumber = 1
ORDER BY publishedAtMs DESC
LIMIT 5 ; ` ;
}
// console.time('hosts with newest exploitable cves query');
let newestExploitableHostsResult = await sails . sendNativeQuery ( queryToFindHostsWithNewestExploitableCves ) ;
// console.timeEnd('hosts with newest exploitable cves query');
// console.log(newestExploitableHostsResult);
let newestExploitableHosts = newestExploitableHostsResult . rows . map ( ( host ) => {
return {
displayName : host . displayName ,
affectedSoftware : host . softwareNameAndVersion ,
fleetUrl : ` ${ sails . config . custom . fleetBaseUrl } /hosts/ ${ host . fleetApid } ` ,
cveId : host . cveId ,
yearPublished : host . cveId . split ( '-' ) [ 1 ] ,
} ;
} ) ;
dataForGraphs . newestExploitableHosts = newestExploitableHosts ;
// console.timeEnd(`Dashboard page view action`);
// Respond with view.
return {
... dataForGraphs
} ;
}
} ;