javascript.lang.security.audit.prototype-pollution.prototype-pollution-loop.prototype-pollution-loop

Author
123
Download Count*
License
Possibility of prototype polluting function detected. By adding or modifying attributes of an object prototype, it is possible to create attributes that exist on every object, or replace critical attributes with malicious ones. This can be problematic if the software depends on existence or non-existence of certain attributes, or uses pre-defined attributes of object prototype (such as hasOwnProperty, toString or valueOf). Possible mitigations might be: freezing the object prototype, using an object without prototypes (via Object.create(null) ), blocking modifications of attributes that resolve to object prototype, using Map instead of object.
Run Locally
Run in CI
Defintion
rules:
- id: prototype-pollution-loop
message: "Possibility of prototype polluting function detected. By adding or
modifying attributes of an object prototype, it is possible to create
attributes that exist on every object, or replace critical attributes with
malicious ones. This can be problematic if the software depends on
existence or non-existence of certain attributes, or uses pre-defined
attributes of object prototype (such as hasOwnProperty, toString or
valueOf). Possible mitigations might be: freezing the object prototype,
using an object without prototypes (via Object.create(null) ), blocking
modifications of attributes that resolve to object prototype, using Map
instead of object."
metadata:
cwe:
- "CWE-915: Improperly Controlled Modification of Dynamically-Determined
Object Attributes"
category: security
references:
- https://github.com/HoLyVieR/prototype-pollution-nsec18/blob/master/paper/JavaScript_prototype_pollution_attack_in_NodeJS.pdf
technology:
- typescript
owasp:
- A08:2021 - Software and Data Integrity Failures
subcategory:
- audit
likelihood: LOW
impact: LOW
confidence: LOW
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
languages:
- typescript
- javascript
severity: WARNING
patterns:
- pattern-either:
- pattern: |
$SMTH = $SMTH[$A]
- pattern: |
$SMTH = $SMTH[$A] = ...
- pattern: |
$SMTH = $SMTH[$A] && $Z
- pattern: |
$SMTH = $SMTH[$A] || $Z
- pattern-either:
- pattern-inside: |
for(...) {
...
}
- pattern-inside: |
while(...) {
...
}
- pattern-inside: |
$X.forEach(function $NAME(...) {
...
})
- pattern-not-inside: |
for(var $A = $S; ...; ...) {...}
- pattern-not-inside: |
for($A = $S; ...; ...) {...}
- pattern-not-inside: |
$X.forEach(function $NAME($OBJ, $A,...) {...})
- metavariable-pattern:
patterns:
- pattern-not: '"..."'
- pattern-not: |
`...${...}...`
- pattern-not: |
($A: float)
metavariable: $A
Examples
prototype-pollution-loop.js
function test1(name, value) {
if (name.indexOf('.') === -1) {
this.config[name] = value;
return this;
}
let config = this.config;
name = name.split('.');
const length = name.length;
name.forEach((item, index) => {
if (index === length - 1) {
config[item] = value;
} else {
if (!helper.isObject(config[item])) {
config[item] = {};
}
// ruleid:prototype-pollution-loop
config = config[item];
}
});
return this;
}
function test2(obj, props, value) {
if (typeof props == 'string') {
props = props.split('.');
}
if (typeof props == 'symbol') {
props = [props];
}
var lastProp = props.pop();
if (!lastProp) {
return false;
}
var thisProp;
while ((thisProp = props.shift())) {
if (typeof obj[thisProp] == 'undefined') {
obj[thisProp] = {};
}
// ruleid:prototype-pollution-loop
obj = obj[thisProp];
if (!obj || typeof obj != 'object') {
return false;
}
}
obj[lastProp] = value;
return true;
}
function test3(obj, prop, val) {
const segs = split(prop);
const last = segs.pop();
while (segs.length) {
const key = segs.shift();
// ruleid:prototype-pollution-loop
obj = obj[key] || (obj[key] = {});
}
obj[last] = val;
}
function okTest1(name) {
if (name.indexOf('.') === -1) {
this.config[name] = value;
return this;
}
let config = this.config;
name = name.split('.');
const length = name.length;
name.forEach((item, index) => {
// ok:prototype-pollution-loop
config = config[index];
});
return this;
}
function okTest2(name) {
let config = this.config;
name = name.split('.');
const length = name.length;
for (let i = 0; i < name.length; i++) {
// ok:prototype-pollution-loop
config = config[i];
}
return this;
}
Short Link: https://sg.run/w1DB