Skip to content

Commit 8800e2c

Browse files
committed
Work with a copy of request, vars in the event
In some cases we were attaching parts of the original request to the event with live references in them and ending up modifying the underlying headers or request data when we scrubbed the event. Now we make sure to only attach a copy of the request to the event. We also do the same for frame vars.
1 parent 5722425 commit 8800e2c

File tree

4 files changed

+45
-2
lines changed

4 files changed

+45
-2
lines changed

sentry_sdk/integrations/_wsgi_common.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
from copy import deepcopy
23

34
from sentry_sdk.hub import Hub, _should_send_default_pii
45
from sentry_sdk.utils import AnnotatedValue
@@ -77,7 +78,7 @@ def extract_into_event(self, event):
7778
if data is not None:
7879
request_info["data"] = data
7980

80-
event["request"] = request_info
81+
event["request"] = deepcopy(request_info)
8182

8283
def content_length(self):
8384
# type: () -> int

sentry_sdk/utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import threading
1111
import time
1212
from collections import namedtuple
13+
from copy import copy
1314
from decimal import Decimal
1415
from numbers import Real
1516

@@ -627,7 +628,7 @@ def serialize_frame(
627628
)
628629

629630
if include_local_variables:
630-
rv["vars"] = frame.f_locals
631+
rv["vars"] = copy(frame.f_locals)
631632

632633
return rv
633634

tests/integrations/flask/test_flask.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,3 +816,26 @@ def index():
816816
response = client.get("/")
817817
assert response.status_code == 200
818818
assert response.data == b"hi"
819+
820+
821+
def test_request_not_modified_by_reference(sentry_init, capture_events, app):
822+
sentry_init(integrations=[flask_sentry.FlaskIntegration()])
823+
824+
@app.route("/", methods=["POST"])
825+
def index():
826+
logging.critical("oops")
827+
assert request.get_json() == {"password": "ohno"}
828+
assert request.headers["Authorization"] == "Bearer ohno"
829+
return "ok"
830+
831+
events = capture_events()
832+
833+
client = app.test_client()
834+
client.post(
835+
"/", json={"password": "ohno"}, headers={"Authorization": "Bearer ohno"}
836+
)
837+
838+
(event,) = events
839+
840+
assert event["request"]["data"]["password"] == "[Filtered]"
841+
assert event["request"]["headers"]["Authorization"] == "[Filtered]"

tests/test_scrubber.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,21 @@ def test_custom_denylist(sentry_init, capture_events):
153153
assert meta == {
154154
"my_sensitive_var": {"": {"rem": [["!config", "s"]]}},
155155
}
156+
157+
158+
def test_scrubbing_doesnt_affect_local_vars(sentry_init, capture_events):
159+
sentry_init()
160+
events = capture_events()
161+
162+
try:
163+
password = "cat123"
164+
1 / 0
165+
except ZeroDivisionError:
166+
capture_exception()
167+
168+
(event,) = events
169+
170+
frames = event["exception"]["values"][0]["stacktrace"]["frames"]
171+
(frame,) = frames
172+
assert frame["vars"]["password"] == "[Filtered]"
173+
assert password == "cat123"

0 commit comments

Comments
 (0)