Sverchok is a popular Blender addon for dataflow programming. It's Set Property Mk2 node has a class pollution vulnerability that accepts arbitrary object path to propogate property value which leads to arbitrary python runtime pollution.
An sophisticated attacker can trick victims into loading their malicious model file, which allow attackers to tamper with the python runtime to achieve stealthyly dangerous consequences, such as token stealing, DoS, etc.
The root cause is that the Set Property Mk2 node does not validate the object path. Attacker can use dunder variables to traverse to the global varibles, other modules to pollute runtime states.
# https://github.com/nortikin/sverchok/blob/9315e9d33fa5b459734491af1f91a3320fe423c5/nodes/object_nodes/getsetprop_mk2.py#L302-L315
def process(self):
if len(self.inputs) == 0:
return
data = self.inputs[0].sv_get()
eval_str = apply_alias(self.prop_name, nodetree=self.id_data)
ast_path = ast.parse(eval_str)
# Here should detect if the path is valid
# if double underscore, such as `.__init__.#__globals__` is used, it should be rejected
path = parse_to_path(ast_path.body[0].value)
obj = get_object(path)
try:
if isinstance(obj, (int, float, str, bpy_prop_array)):
obj = get_object(path[:-1])
p_type, value = path[-1]
if p_type == "attr":
setattr(obj, value, data[0][0])
else:
obj[value] = data[0][0]
else:
assign_data(obj, data)
except Exception as err:
print(err)This section shows how to exploit the vulnerability to steal github token.
-
Add a
Set Property Mk2node with the object pathbpy.utils.execfile.__globals__["_sys"].modules["sverchok"].utils.sv_gist_tools.API_URL, which value is the github gist url that sverchok refers to. -
Add a
Simple Textnode and set the value to the attacker's http server which will overwrite the github gist's url that sverchok refers to.
- Export to github gist, triggering the attack. The token is exfiltrating through the http request header.
Validate the object path in Set Property Mk2 node in the get_object function to detect and reject the dunder variables.
# https://github.com/nortikin/sverchok/blob/9315e9d33fa5b459734491af1f91a3320fe423c5/nodes/object_nodes/getsetprop_mk2.py#L68
def get_object(path):
'''
- access the object specified from a path generated by parse_to_path
- this will fail if path is invalid
'''
curr_object = globals()[path[0][1]]
for t, value in path[1:]:
# Patch at here:
if value.startswith("__") or value.endswith("__"):
throw ValueError("Invalid path")
if t == "attr":
curr_object = getattr(curr_object, value)
elif t == "key":
curr_object = curr_object[value]
return curr_object- CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes
- Report: Django Unicorn is Vulnerable to Class Pollution
- Report: Class Pollution leading to RCE in pydash
- Blog: Class Pollution
- Blog: Class Pollution Gadgets in Jinja Leading to RCE
- Python Official: Dunder Names Specification

