Skip to content

Commit 7f921f2

Browse files
committed
pymongo: Scan _doc & scan a bunch more operations
1 parent 4af94ea commit 7f921f2

2 files changed

Lines changed: 440 additions & 15 deletions

File tree

aikido_zen/sinks/pymongo.py

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,52 @@ def _func_pipeline(func, instance, args, kwargs):
6161
)
6262

6363

64+
@before
65+
def _func_filter_first_update_second(func, instance, args, kwargs):
66+
"""Collection.func(filter, update, ...) — scans both filter and update"""
67+
operation = f"pymongo.collection.Collection.{func.__name__}"
68+
register_call(operation, "nosql_op")
69+
70+
nosql_filter = get_argument(args, kwargs, 0, "filter")
71+
if nosql_filter:
72+
vulns.run_vulnerability_scan(
73+
kind="nosql_injection",
74+
op=operation,
75+
args=(nosql_filter,),
76+
)
77+
78+
nosql_update = get_argument(args, kwargs, 1, "update")
79+
if nosql_update:
80+
vulns.run_vulnerability_scan(
81+
kind="nosql_injection",
82+
op=operation,
83+
args=(nosql_update,),
84+
)
85+
86+
87+
@before
88+
def _func_filter_first_replacement_second(func, instance, args, kwargs):
89+
"""Collection.func(filter, replacement, ...) — scans both filter and replacement"""
90+
operation = f"pymongo.collection.Collection.{func.__name__}"
91+
register_call(operation, "nosql_op")
92+
93+
nosql_filter = get_argument(args, kwargs, 0, "filter")
94+
if nosql_filter:
95+
vulns.run_vulnerability_scan(
96+
kind="nosql_injection",
97+
op=operation,
98+
args=(nosql_filter,),
99+
)
100+
101+
nosql_replacement = get_argument(args, kwargs, 1, "replacement")
102+
if nosql_replacement:
103+
vulns.run_vulnerability_scan(
104+
kind="nosql_injection",
105+
op=operation,
106+
args=(nosql_replacement,),
107+
)
108+
109+
64110
@before
65111
def _bulk_write(func, instance, args, kwargs):
66112
requests = get_argument(args, kwargs, 0, "requests")
@@ -77,12 +123,22 @@ def _bulk_write(func, instance, args, kwargs):
77123
op=operation,
78124
args=(nosql_filter,),
79125
)
126+
# Also scan the update/replacement doc for UpdateOne, UpdateMany, ReplaceOne
127+
nosql_doc = getattr(request, "_doc", None)
128+
if nosql_doc:
129+
vulns.run_vulnerability_scan(
130+
kind="nosql_injection",
131+
op=operation,
132+
args=(nosql_doc,),
133+
)
80134

81135

82136
def patch_collection(m):
83137
"""
84138
patching pymongo.collection
85139
- patches Collection.*(filter, ...)
140+
- patches Collection.*(filter, update, ...)
141+
- patches Collection.*(filter, replacement, ...)
86142
- patches Collection.*(..., filter, ...)
87143
- patches Collection.*(pipeline, ...)
88144
- patches Collection.bulk_write
@@ -96,20 +152,25 @@ def patch_collection(m):
96152
if original_collection_class.__module__ != "pymongo.collection":
97153
return
98154

99-
# func(filter, ...)
100-
patch_function(m, "Collection.replace_one", _func_filter_first)
101-
patch_function(m, "Collection.update_one", _func_filter_first)
102-
patch_function(m, "Collection.update_many", _func_filter_first)
155+
# func(filter, ...) — only filter, no second payload arg
103156
patch_function(m, "Collection.delete_one", _func_filter_first)
104157
patch_function(m, "Collection.delete_many", _func_filter_first)
105158
patch_function(m, "Collection.count_documents", _func_filter_first)
106159
patch_function(m, "Collection.find_one_and_delete", _func_filter_first)
107-
patch_function(m, "Collection.find_one_and_replace", _func_filter_first)
108-
patch_function(m, "Collection.find_one_and_update", _func_filter_first)
109160
patch_function(m, "Collection.find", _func_filter_first)
110161
patch_function(m, "Collection.find_raw_batches", _func_filter_first)
111162
# find_one not present in list since find_one calls find function.
112163

164+
# func(filter, update, ...) — scans filter + update
165+
patch_function(m, "Collection.update_one", _func_filter_first_update_second)
166+
patch_function(m, "Collection.update_many", _func_filter_first_update_second)
167+
patch_function(m, "Collection.find_one_and_update", _func_filter_first_update_second)
168+
169+
# func(filter, replacement, ...) — scans filter + replacement
170+
patch_function(m, "Collection.replace_one", _func_filter_first_replacement_second)
171+
patch_function(m, "Collection.find_one_and_replace", _func_filter_first_replacement_second)
172+
# find_one not present in list since find_one calls find function.
173+
113174
# func(..., filter, ...)
114175
patch_function(m, "Collection.distinct", _func_filter_second)
115176

0 commit comments

Comments
 (0)