Skip to content

Commit 52a5d78

Browse files
committed
feat(lbsa-20201130): update references, vendor, notes
CSAF 2.0: - Updated references - Updated vendor to "LoopBack" - Reorganised notes OSV: - Updated references Signed-off-by: Rifa Achrinza <[email protected]>
1 parent 06f2805 commit 52a5d78

File tree

4 files changed

+150
-55
lines changed

4 files changed

+150
-55
lines changed

advisories/lbsa-20201130.csaf.json

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,57 +14,34 @@
1414
}
1515
},
1616
"lang": "en",
17-
"notes": [
18-
{
19-
"audience": "all",
20-
"category": "description",
21-
"text": "It's a similar issue as https://snyk.io/vuln/SNYK-JS-LODASH-73638, where the following description is quoted from.\n\n> Prototype Pollution is a vulnerability affecting JavaScript. Prototype Pollution refers to the ability to inject properties into existing JavaScript language construct prototypes, such as objects. JavaScript allows all Object attributes to be altered, including their magical attributes such as `_proto_`, `constructor` and `prototype`. An attacker manipulates these attributes to overwrite, or pollute, a JavaScript application object prototype of the base object by injecting other values. Properties on the Object.prototype are then inherited by all the JavaScript objects through the prototype chain. When that happens, this leads to either denial of service by triggering JavaScript exceptions, or it tampers with the application source code to force the code path that the attacker injects, thereby leading to remote code execution.\n>\n> There are two main ways in which the pollution of prototypes occurs:\n>\n> - Unsafe Object recursive merge\n> - Property definition by path"
22-
},
23-
{
24-
"audience": "all",
25-
"category": "summary",
26-
"text": "`@loopback/rest` allows REST APIs to have `constructor` in the JSON payload, which is vulnerable to prototype pollution."
27-
}
28-
],
2917
"publisher": {
3018
"category": "vendor",
31-
"name": "The LoopBack Maintainers",
19+
"name": "LoopBack",
3220
"namespace": "https://loopback.io"
3321
},
3422
"references": [
3523
{
3624
"category": "self",
37-
"summary": "Security Advisory 11-30-2020 CSAF document",
25+
"summary": "LoopBack Security Advisory 11-30-2020 CSAF document",
3826
"url": "https://loopback.io/doc/en/sec/lbsa-2020-11-30.csaf.json"
3927
},
4028
{
4129
"category": "self",
42-
"summary": "Security Advisory 11-30-2020 HTML document",
30+
"summary": "LoopBack Security Advisory 11-30-2020 HTML document",
4331
"url": "https://loopback.io/doc/en/sec/Security-advisory-11-30-2020.html"
44-
},
45-
{
46-
"summary": "NVD - CVE-2020-4988 Detail",
47-
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-4988"
48-
},
49-
{
50-
"summary": "CVE-2020-4988 CVE Record",
51-
"url": "https://www.cve.org/CVERecord?id=CVE-2020-4988"
52-
},
53-
{
54-
"summary": "NPM",
55-
"url": "https://www.npmjs.com/package/@loopback/rest"
56-
},
57-
{
58-
"summary": "X-Force Vulnerability Report",
59-
"url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/192706"
6032
}
6133
],
62-
"title": "Security Advisory 11-30-2020",
34+
"title": "LoopBack Security Advisory 11-30-2020",
6335
"tracking": {
64-
"current_release_date": "2022-03-07T03:42:00.000Z",
36+
"current_release_date": "2022-03-07T13:53:00.000Z",
6537
"id": "LBSA-20201130",
6638
"initial_release_date": "2022-01-18T00:00:00.000Z",
6739
"revision_history": [
40+
{
41+
"date": "2022-03-07T13:53:00.000Z",
42+
"number": "2.1.0",
43+
"summary": "Updated vendor; Updated references; Reorganised notes."
44+
},
6845
{
6946
"date": "2022-03-07T03:42:00.000Z",
7047
"number": "2.0.0",
@@ -87,7 +64,7 @@
8764
}
8865
],
8966
"status": "final",
90-
"version": "2.0.0"
67+
"version": "2.1.0"
9168
}
9269
},
9370
"product_tree": {
@@ -2106,7 +2083,7 @@
21062083
}
21072084
],
21082085
"category": "vendor",
2109-
"name": "The LoopBack Maintainers"
2086+
"name": "LoopBack"
21102087
}
21112088
]
21122089
},
@@ -2308,10 +2285,31 @@
23082285
},
23092286
"references": [
23102287
{
2288+
"category": "self",
23112289
"summary": "GitHub Pull Request",
23122290
"url": "https://github.com/loopbackio/loopback-next/pull/6676"
23132291
},
23142292
{
2293+
"category": "self",
2294+
"summary": "GitHub Commit",
2295+
"url": "https://github.com/loopbackio/loopback-next/tree/ae0b9936e7eadbf6f0ee7c72e1a04b87dda7c2c5"
2296+
},
2297+
{
2298+
"category": "self",
2299+
"summary": "NVD CVE Detail",
2300+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-4988"
2301+
},
2302+
{
2303+
"category": "self",
2304+
"summary": "CVE Record",
2305+
"url": "https://www.cve.org/CVERecord?id=CVE-2020-4988"
2306+
},
2307+
{
2308+
"summary": "NPM",
2309+
"url": "https://www.npmjs.com/package/@loopback/rest"
2310+
},
2311+
{
2312+
"category": "self",
23152313
"summary": "X-Force Vulnerability Report",
23162314
"url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/192706"
23172315
}

advisories/lbsa-20201130.osv.json

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@
214214
},
215215
"details": "It's a similar issue as https://snyk.io/vuln/SNYK-JS-LODASH-73638, where the following description is quoted from.\n\n> Prototype Pollution is a vulnerability affecting JavaScript. Prototype Pollution refers to the ability to inject properties into existing JavaScript language construct prototypes, such as objects. JavaScript allows all Object attributes to be altered, including their magical attributes such as `_proto_`, `constructor` and `prototype`. An attacker manipulates these attributes to overwrite, or pollute, a JavaScript application object prototype of the base object by injecting other values. Properties on the Object.prototype are then inherited by all the JavaScript objects through the prototype chain. When that happens, this leads to either denial of service by triggering JavaScript exceptions, or it tampers with the application source code to force the code path that the attacker injects, thereby leading to remote code execution.\n>\n> There are two main ways in which the pollution of prototypes occurs:\n>\n> - Unsafe Object recursive merge\n> - Property definition by path",
216216
"id": "LBSA-20201130",
217-
"modified": "2022-03-06T00:13:54.000Z",
217+
"modified": "2022-03-07T13:53:00.000Z",
218218
"references": [
219219
{
220220
"type": "ADVISORY",
@@ -225,20 +225,32 @@
225225
"url": "https://loopback.io/doc/en/sec/Security-advisory-11-30-2020.html"
226226
},
227227
{
228-
"type": "ADVISORY",
229-
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-4988"
230-
},
231-
{
232-
"type": "ADVISORY",
233-
"url": "https://www.cve.org/CVERecord?id=CVE-2020-4988"
228+
"type": "PACKAGE",
229+
"url": "https://loopback.io"
234230
},
235231
{
236232
"type": "PACKAGE",
237233
"url": "https://www.npmjs.com/package/@loopback/rest"
238234
},
239235
{
240-
"type": "REPORT",
236+
"type": "WEB",
241237
"url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/192706"
238+
},
239+
{
240+
"type": "WEB",
241+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-4988"
242+
},
243+
{
244+
"type": "WEB",
245+
"url": "https://github.com/loopbackio/loopback-next/pull/6676"
246+
},
247+
{
248+
"type": "WEB",
249+
"url": "https://github.com/loopbackio/loopback-next/tree/ae0b9936e7eadbf6f0ee7c72e1a04b87dda7c2c5"
250+
},
251+
{
252+
"type": "WEB",
253+
"url": "https://www.cve.org/CVERecord?id=CVE-2020-4988"
242254
}
243255
],
244256
"schema_version": "1.2.0",

scripts/advisories/validate-csaf20.ts

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ glob(path.resolve(__dirname, csaf20DocumentGlob), async (err, matches) => {
2727
distribution: validateDistribution(fileContents),
2828
productTree: validateProductTree(fileContents),
2929
publisher: validatePublisher(fileContents),
30+
references: validateReferences(fileContents),
3031
};
3132

3233
const validationResultsValues = Object.values(validationResults);
@@ -160,22 +161,21 @@ function validateProductTree(fileContents: any): ValidationResult {
160161
const productTree = fileContents.product_tree.branches;
161162
const errors: ValidationResult['errors'] = [];
162163
const lbRootBranchIndex = (productTree as any[])?.findIndex(
163-
v => v.name === 'The LoopBack Maintainers',
164+
v => v.name === 'LoopBack',
164165
);
165166

166167
if (lbRootBranchIndex > -1) {
167168
const lbRootBranch = productTree[lbRootBranchIndex];
168169
if (lbRootBranch.category !== 'vendor') {
169170
errors.push({
170171
instancePath: `/product_tree/branches/${lbRootBranchIndex}/category`,
171-
message:
172-
'category must be `vendor` for `The LoopBack Maintainers` vendor root branch.',
172+
message: 'category must be `vendor` for `LoopBack` vendor root branch.',
173173
});
174174
}
175175
} else {
176176
errors.push({
177177
instancePath: '/product_tree/branches',
178-
message: '`The LoopBack Maintainers` vendor root branch must exist.',
178+
message: '`LoopBack` vendor root branch must exist.',
179179
});
180180
}
181181

@@ -196,10 +196,10 @@ function validatePublisher(fileContents: any): ValidationResult {
196196
});
197197
}
198198

199-
if (publisher.name !== 'The LoopBack Maintainers') {
199+
if (publisher.name !== 'LoopBack') {
200200
errors.push({
201201
instancePath: '/document/publisher/name',
202-
message: 'name must equal `The LoopBack Maintainers`',
202+
message: 'name must equal `LoopBack`',
203203
});
204204
}
205205

@@ -215,3 +215,83 @@ function validatePublisher(fileContents: any): ValidationResult {
215215
errors,
216216
};
217217
}
218+
219+
function validateReferences(fileContents: any): ValidationResult {
220+
const errors: ValidationResult['errors'] = [];
221+
const documentReferences = fileContents.document.references;
222+
const vulnerabilityReferences = fileContents.vulnerabilities.flatMap(
223+
x => x.references,
224+
);
225+
226+
// Ensure references with standardised summary uses a consistent URL.
227+
228+
// Do not re-order this array.
229+
const allReferences = [...documentReferences, ...vulnerabilityReferences];
230+
231+
const refRegexMapping: Record<string, RegExp> = {
232+
'CVE Record':
233+
/^https:\/\/www\.cve\.org\/CVERecord\?id=CVE-[1-9][0-9]{3}-\d{4}$/,
234+
NPM: /^https:\/\/www\.npmjs\.com\/package\/([a-z0-9-]|(@[a-z0-9._-]+\/))[a-z0-9._-]+$/,
235+
'NVD CVE Detail':
236+
/^https:\/\/nvd\.nist\.gov\/vuln\/detail\/CVE-[1-9][0-9]{3}-\d{4}$/,
237+
'GitHub Commit':
238+
/^(https:\/\/github\.com\/loopbackio\/[A-Za-z0-9._-]+\/tree\/[a-z0-9]+)$/,
239+
'GitHub Pull Request':
240+
/^(https:\/\/github\.com\/loopbackio\/[A-Za-z0-9._-]+\/pull\/[1-9]\d*)$/,
241+
'X-Force Vulnerability Report':
242+
/^https:\/\/exchange\.xforce\.ibmcloud\.com\/vulnerabilities\/[1-9]\d*$/,
243+
};
244+
245+
for (let i = 0; i < allReferences.length; i++) {
246+
const ref = allReferences[i];
247+
const matchedRegex = refRegexMapping[ref.summary];
248+
249+
if (matchedRegex) {
250+
if (!matchedRegex.test(ref.url)) {
251+
// Hacky way of paritally reconstructing the instance path.
252+
const baseInstancePath =
253+
i < documentReferences.length
254+
? '/document/references/'
255+
: '/vulnerabilities/?/';
256+
const refIndex =
257+
i < documentReferences.length ? i : i - documentReferences.length;
258+
259+
errors.push({
260+
instancePath: baseInstancePath + refIndex + '/url',
261+
message: `url must match \`${matchedRegex}\`.`,
262+
});
263+
}
264+
}
265+
}
266+
267+
// Ensure no duplicate URLs between document-level and vulnerability-level
268+
// references
269+
const documentReferenceUrls = documentReferences.map(x => x.url);
270+
const vulnerabilityReferenceUrls = vulnerabilityReferences.map(x => x.url);
271+
272+
if (documentReferenceUrls.length >= vulnerabilityReferenceUrls) {
273+
for (let i = 0; i < documentReferenceUrls.length; i++) {
274+
if (vulnerabilityReferenceUrls.includes(documentReferenceUrls[i])) {
275+
errors.push({
276+
instancePath: `/document/references/${i}/url`,
277+
message:
278+
'url must not be duplicate in `/vulnerabilities/*/references/*/url`.',
279+
});
280+
}
281+
}
282+
} else {
283+
for (let i = 0; i < vulnerabilityReferenceUrls.length; i++) {
284+
if (documentReferenceUrls.includes(vulnerabilityReferenceUrls[i])) {
285+
errors.push({
286+
instancePath: `/vulnerabilities/?/references/${i}/url`,
287+
message: 'url not must be duplicate in `/document/references/*/url',
288+
});
289+
}
290+
}
291+
}
292+
293+
return {
294+
isValid: errors.length < 1,
295+
errors,
296+
};
297+
}

scripts/advisories/validate-osv.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,6 @@ function validateAffectedVersions(fileContents: any): ValidationResult {
113113
' <' +
114114
semverEvents.find(x => x.fixed).fixed;
115115

116-
console.log(semverRange);
117-
118116
for (let i = 0; i < versions.length; i++) {
119117
const version = versions[i];
120118

@@ -161,7 +159,7 @@ function validateCSAF20Sync(
161159
}
162160

163161
// Summary sync
164-
const csaf20Summary = csaf20Document.document.notes.find(
162+
const csaf20Summary = csaf20Document.vulnerabilities[0].notes?.find(
165163
x => x.category === 'summary',
166164
).text;
167165
const osvSummary = osvDocument.summary;
@@ -174,7 +172,7 @@ function validateCSAF20Sync(
174172
}
175173

176174
// Description / Details sync
177-
const csaf2SDescription = csaf20Document.document.notes.find(
175+
const csaf2SDescription = csaf20Document.vulnerabilities[0].notes.find(
178176
x => x.category === 'description',
179177
).text;
180178
const osvDetails = osvDocument.details;
@@ -226,8 +224,15 @@ function validateCSAF20Sync(
226224
}
227225

228226
// References sync
229-
const csaf20References = csaf20Document.document.references.map(x => x.url);
230-
const osvReferences = osvDocument.references.map(x => x.url);
227+
const csaf20References = [
228+
...csaf20Document.document.references.map(x => x.url),
229+
...csaf20Document.vulnerabilities
230+
.flatMap(x => x.references)
231+
.map(x => x.url),
232+
];
233+
const osvReferences = osvDocument.references
234+
.map(x => x.url)
235+
.filter(x => x !== 'https://loopback.io');
231236

232237
if (osvReferences.length >= csaf20References.length) {
233238
for (let i = 0; i < osvReferences.length; i++) {

0 commit comments

Comments
 (0)