Skip to content

Commit

Permalink
fix: don't allow object paths that reference dunder-method attributes…
Browse files Browse the repository at this point in the history
… for functions like get()
  • Loading branch information
dgilland committed Jan 29, 2023
1 parent 1947d2a commit 6ff0831
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/pydash/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ def _base_get_item(obj, key, default=UNSET):
def _base_get_object(obj, key, default=UNSET):
value = _base_get_item(obj, key, default=UNSET)
if value is UNSET:
_raise_if_restricted_key(key)
value = default
try:
value = getattr(obj, key)
Expand All @@ -186,6 +187,13 @@ def _base_get_object(obj, key, default=UNSET):
return value


def _raise_if_restricted_key(key):
# Prevent access to dunder-methods since this could expose access to globals through leaky
# attributes such as obj.__init__.__globals__.
if len(key) > 4 and key.isascii() and key.startswith("__") and key.endswith("__"):
raise KeyError(f"access to restricted key {key!r} is not allowed")


def base_set(obj, key, value, allow_override=True):
"""
Set an object's `key` to `value`. If `obj` is a ``list`` and the `key` is the next available
Expand Down Expand Up @@ -213,6 +221,7 @@ def base_set(obj, key, value, allow_override=True):
obj[:] = (obj + [None] * key)[:key]
obj.append(value)
elif (allow_override or not hasattr(obj, key)) and obj is not None:
_raise_if_restricted_key(key)
setattr(obj, key, value)

return obj
Expand Down
24 changes: 24 additions & 0 deletions tests/test_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,30 @@ def test_get__should_not_populate_defaultdict():
assert data == {}


@parametrize(
"obj,path",
[
(helpers.Object(), "__init__"),
(helpers.Object(subobj=helpers.Object()), "subobj.__init__"),
(namedtuple("a", ["a"])(a=1), "__len__"),
],
)
def test_get__raises_for_objects_when_path_restricted(obj, path):
with pytest.raises(KeyError, match="access to restricted key"):
_.get(obj, path)


@parametrize(
"obj,path",
[
({}, "__init__"),
([], "__contains__"),
],
)
def test_get__does_not_raise_for_dict_or_list_when_path_restricted(obj, path):
assert _.get(obj, path) is None


@parametrize(
"case,expected",
[
Expand Down

0 comments on commit 6ff0831

Please sign in to comment.