Copy let afProjectId;
if (data.vulnerability_projects) {
for (let i = 0; i < data.vulnerability_projects.length; i++) {
if (data.vulnerability_projects[i].id) {
afProjectId = data.vulnerability_projects[i].id;
break;
}
}
}
if (!afProjectId) {
return {
decision: {
status: 'abort',
message: 'afProjectId is undefined',
},
};
}
return {
data: {
af_project_id: afProjectId,
af_vuln_id: data?.vulnerability_id
},
request: {
body: buildRequestBody()
}
};
function buildRequestBody() {
const fields = [];
let title = '';
if (data.vulnerability_title) {
title = '[SECURITY][VULNERABILITY] ' + data.vulnerability_title;
}
Array.push(fields, {
from: null,
op: 'add',
path: '/fields/System.Title',
value: title
});
let priority = 4;
if (data.vulnerability_priority === 'Critical') {
priority = 1;
}
else if (data.vulnerability_priority === 'High') {
priority = 2;
}
else if (data.vulnerability_priority === 'Medium') {
priority = 3;
}
else if (data.vulnerability_priority === 'Low') {
priority = 4;
}
else if (data.vulnerability_priority === 'Info') {
priority = 4;
}
Array.push(fields, {
from: null,
op: 'add',
path: '/fields/Microsoft.VSTS.Common.Priority',
value: priority
});
if (data.vulnerability_priority) {
Array.push(fields, {
from: null,
op: 'add',
path: '/fields/System.Tags',
value: data.vulnerability_priority + ', Security Vulnerability'
});
}
let description = '';
if (data.vulnerability_title) {
description += '<h1>[SECURITY][VULNERABILITY] ' + data.vulnerability_title + '</h1><br/>';
}
if (data.vulnerability_description) {
const sanitizedDescription = String.replace(data.vulnerability_description, m/\r\n|\n|\r/gi, '<br>');
description += '<h2>Description</h2><p>' + sanitizedDescription + '</p>';
}
if (data.vulnerability_affected_asset_name) {
description += '<h2>Affected Asset</h2><ul><li>' + data.vulnerability_affected_asset_name + '</li></ul>';
}
else if (data.vulnerability_affected_assets) {
description += '<h2>Affected Asset(s)</h2><ul>';
for (let i = 0; i < data.vulnerability_affected_assets.length; i++) {
if (data.vulnerability_affected_assets[i].asset?.name) {
description += '<li>' + data.vulnerability_affected_assets[i].asset.name + '</li>';
}
}
description += '</ul>';
}
let cvssScore;
let cvssVector;
if (data.vulnerability_priority && data.vulnerability_tags) {
for (let i = 0; i < data.vulnerability_tags.length; i++) {
if (data.vulnerability_tags[i] =~ m/CVSSv3.1 Base Score: /) {
cvssScore = String.replace(data.vulnerability_tags[i], 'CVSSv3.1 Base Score: ', '');
}
if (data.vulnerability_tags[i] =~ m/CVSSv3.1 Temporal Score: /) {
cvssScore = String.replace(data.vulnerability_tags[i], 'CVSSv3.1 Temporal Score: ', '');
}
if (data.vulnerability_tags[i] =~ m/CVSSv3.1 Environmental Score: /) {
cvssScore = String.replace(data.vulnerability_tags[i], 'CVSSv3.1 Environmental Score: ', '');
}
if (data.vulnerability_tags[i] =~ m/CVSS:3.1\//) {
cvssVector = String.replace(data.vulnerability_tags[i], 'CVSS:3.1/', '');
}
}
if (cvssScore && cvssVector) {
description +=
"<h2>Technical Severity</h2>" +
"<table style='text-align: center; vertical-align: middle; font-size:15px;'>" +
"<thead>" +
"<td><b>Rating</b></td>" +
"<td><b>CVSSv3.1 Score</b></td>" +
"</thead>" +
"<tbody>" +
"<td>" + data.vulnerability_priority + "</td>" +
"<td>" + cvssScore + "</td>" +
"</tbody>" +
"</table>" +
"<p>CVSS 3.1 Vector String: <a href='https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?version=3.1&vector=" + cvssVector + "'>" + cvssVector + "</a></p>";
}
else {
description +=
"<h2>Technical Severity</h2>" +
"<table style='text-align: center; vertical-align: middle; font-size:15px;'>" +
"<thead>" +
"<td><b>Rating</b></td>" +
"</thead>" +
"<tbody>" +
"<td>" + data.vulnerability_priority + "</td>" +
"</tbody>" +
"</table>";
}
}
if (data.vulnerability_likelihood_of_exploitation && data.vulnerability_attack_scenario) {
const sanitizedAttackScenario = String.replace(data.vulnerability_attack_scenario, m/\r\n|\n|\r/gi, '<br>');
description +=
"<h2>Attack Scenario (Technical Risk)</h2>" +
"<p>Likelihood of Exploitation: " + data.vulnerability_likelihood_of_exploitation + "/10</p>" +
"<p>" + sanitizedAttackScenario + "</p>";
}
if (data.vulnerability_remediation_recommendation) {
const sanitizedRemediationRecommendation = String.replace(data.vulnerability_remediation_recommendation, m/\r\n|\n|\r/gi, '<br>');
description += "<h2>Recommendations</h2><p>" + sanitizedRemediationRecommendation + "</p>";
}
if (data.vulnerability_notes && data.vulnerability_notes.length > 0) {
description += "<h2>Notes</h2>";
for (let i = 0; i < data.vulnerability_notes.length; i++) {
if (data.vulnerability_notes[i].note) {
const sanitizedNote = String.replace(data.vulnerability_notes[i].note, m/\r\n|\n|\r/gi, '<br>');
description += '<p>' + sanitizedNote + '</p>';
}
}
}
if (data.vulnerability_steps_to_reproduce) {
const sanitizedPOC = String.replace(data.vulnerability_steps_to_reproduce, m/\r\n|\n|\r/gi, '<br>');
description += "<h2>Steps to Reproduce</h2><p>" + sanitizedPOC + "</p>";
}
if (data.vulnerability_tags) {
description += "<h2>Tags</h2><ul>";
for (let i = 0; i < data.vulnerability_tags.length; i++) {
description += '<li>' + data.vulnerability_tags[i] + '</li>';
}
description += '</ul>';
}
Array.push(fields, {
from: null,
op: 'add',
path: "/fields/System.Description",
value: description
});
return fields;
}