GHSA-82JV-9WJW-PQH6
Vulnerability from github – Published: 2024-04-17 22:26 – Updated: 2024-04-17 22:26Summary
A prototype pollution in derby can crash the application, if the application author has atypical HTML templates that feed user input into an object key.
Attribute keys are almost always developer-controlled, not end-user-controlled, so this shouldn't be an issue in practice for most applications.
Details
emit(context: Context, target: T) {
const node = traverseAndCreate(context.controller, this.segments);
node[this.lastSegment] = target;
this.addListeners(target, node, this.lastSegment);
}
The emit() function in src/templates/templates.ts is called without sanitizing the variable this.lastSegment. The variable this.lastSegment can be set to __proto__, and this will pollute the prototype of Javascipt Object (node['__proto__'] = target).
PoC
To reproduce this vulnerability, you can adjust the test case ignores DOM mutations in components\' create() in test/dom/ComponentHarness.mocha.js.
it('ignores DOM mutations in components\' create()', function() {
function Box() {}
Box.view = {
is: 'box',
- source: '<index:><div class="box" as="boxElement"></div>'
+ source: '<index:><div class="box" as="__proto__"></div>'
};
Box.prototype.create = function() {
this.boxElement.className = 'box-changed-in-create';
};
var harness = runner.createHarness('<view is="box" />', Box);
expect(harness).to.render('<div class="box"></div>');
});
When as attribute is controlled by attackers, the variable in this.lastSegment will exactly take value__proto__ and prototype pollution happens.
Patch
Add a check on this.lastSegment can prevent this attack.
emit(context: Context, target: T) {
const node = traverseAndCreate(context.controller, this.segments);
+ if (this.lastSegment.includes('__proto__') || this.lastSegment.includes('prototype')) {
+ throw new Error('Unsafe code detected');
+ }
node[this.lastSegment] = target;
this.addListeners(target, node, this.lastSegment);
}
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.3.1"
},
"package": {
"ecosystem": "npm",
"name": "derby"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.3.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.0.1"
},
"package": {
"ecosystem": "npm",
"name": "derby"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.0.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.0.0-beta.10"
},
"package": {
"ecosystem": "npm",
"name": "derby"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0-beta1"
},
{
"fixed": "4.0.0-beta.11"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-1321"
],
"github_reviewed": true,
"github_reviewed_at": "2024-04-17T22:26:37Z",
"nvd_published_at": null,
"severity": "LOW"
},
"details": "### Summary\nA prototype pollution in derby can crash the application, if the application author has atypical HTML templates that feed user input into an object key.\n\nAttribute keys are almost always developer-controlled, not end-user-controlled, so this shouldn\u0027t be an issue in practice for most applications.\n\n### Details\n```\nemit(context: Context, target: T) {\n const node = traverseAndCreate(context.controller, this.segments);\n node[this.lastSegment] = target;\n this.addListeners(target, node, this.lastSegment);\n}\n```\nThe emit() function in src/templates/templates.ts is called without sanitizing the variable `this.lastSegment `. The variable `this.lastSegment ` can be set to `__proto__`, and this will pollute the prototype of Javascipt Object (`node[\u0027__proto__\u0027] = target`).\n\n### PoC\nTo reproduce this vulnerability, you can adjust the test case `ignores DOM mutations in components\\\u0027 create()` in `test/dom/ComponentHarness.mocha.js`.\n\n```\nit(\u0027ignores DOM mutations in components\\\u0027 create()\u0027, function() {\n function Box() {}\n Box.view = {\n is: \u0027box\u0027,\n- source: \u0027\u003cindex:\u003e\u003cdiv class=\"box\" as=\"boxElement\"\u003e\u003c/div\u003e\u0027\n+ source: \u0027\u003cindex:\u003e\u003cdiv class=\"box\" as=\"__proto__\"\u003e\u003c/div\u003e\u0027\n };\n Box.prototype.create = function() {\n this.boxElement.className = \u0027box-changed-in-create\u0027;\n };\n var harness = runner.createHarness(\u0027\u003cview is=\"box\" /\u003e\u0027, Box);\n expect(harness).to.render(\u0027\u003cdiv class=\"box\"\u003e\u003c/div\u003e\u0027);\n});\n```\nWhen `as` attribute is controlled by attackers, the variable in `this.lastSegment` will exactly take value` __proto__` and prototype pollution happens.\n\n### Patch\nAdd a check on `this.lastSegment` can prevent this attack.\n```\nemit(context: Context, target: T) {\n const node = traverseAndCreate(context.controller, this.segments);\n+ if (this.lastSegment.includes(\u0027__proto__\u0027) || this.lastSegment.includes(\u0027prototype\u0027)) {\n+ throw new Error(\u0027Unsafe code detected\u0027);\n+ }\n node[this.lastSegment] = target;\n this.addListeners(target, node, this.lastSegment);\n}\n```\n",
"id": "GHSA-82jv-9wjw-pqh6",
"modified": "2024-04-17T22:26:37Z",
"published": "2024-04-17T22:26:37Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/derbyjs/derby/security/advisories/GHSA-82jv-9wjw-pqh6"
},
{
"type": "WEB",
"url": "https://github.com/derbyjs/derby/commit/24524e96f36976883c7c619811320428536bd4d0"
},
{
"type": "WEB",
"url": "https://github.com/derbyjs/derby/commit/465a0c2f6a77361eda4a09b77a8c94ba6a9da440"
},
{
"type": "PACKAGE",
"url": "https://github.com/derbyjs/derby"
}
],
"schema_version": "1.4.0",
"severity": [],
"summary": "Prototype pollution in emit function"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.