Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 29 additions & 54 deletions sentry_sdk/integrations/aws_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@
CLOUD_PLATFORM,
CLOUD_PROVIDER,
)
from sentry_sdk.scope import Scope, should_send_default_pii
from sentry_sdk.scope import Scope
from sentry_sdk.traces import SegmentNameSource
from sentry_sdk.utils import (
AnnotatedValue,
TimeoutThread,
capture_internal_exceptions,
ensure_integration_enabled,
event_from_exception,
has_data_collection_enabled,
logger,
reraise,
)
Expand Down Expand Up @@ -180,31 +179,21 @@ def sentry_handler(
"httpMethod"
]

data_collection = client.options["data_collection"]
if "queryStringParameters" in request_data:
qs = request_data["queryStringParameters"]
if qs:
if has_data_collection_enabled(client.options):
filtered_qs = _apply_key_value_collection_filtering(
items=qs,
behaviour=client.options["data_collection"][
"url_query_params"
],
)
if filtered_qs:
additional_attributes["url.query"] = urlencode(filtered_qs)
elif should_send_default_pii():
additional_attributes["url.query"] = urlencode(qs)

if not scope._user:
if has_data_collection_enabled(client.options):
if client.options["data_collection"]["user_info"]:
user_info = _get_user_from_event(request_data)
if user_info:
scope.set_user(user_info)
elif should_send_default_pii():
user_info = _get_user_from_event(request_data)
if user_info:
scope.set_user(user_info)
filtered_qs = _apply_key_value_collection_filtering(
items=qs,
behaviour=data_collection["url_query_params"],
)
if filtered_qs:
additional_attributes["url.query"] = urlencode(filtered_qs)

if not scope._user and data_collection["user_info"]:
user_info = _get_user_from_event(request_data)
if user_info:
scope.set_user(user_info)

sampling_context = {
"aws_event": aws_event,
Expand Down Expand Up @@ -397,50 +386,36 @@ def event_processor(

request["url"] = _get_url(aws_event, aws_context)

client_options = sentry_sdk.get_client().options
data_collection = client_options["data_collection"]

if "queryStringParameters" in aws_event:
query_string = aws_event["queryStringParameters"]
client_options = sentry_sdk.get_client().options
if has_data_collection_enabled(client_options):
if query_string:
filtered_qs = _apply_key_value_collection_filtering(
items=query_string,
behaviour=client_options["data_collection"]["url_query_params"],
)
if filtered_qs:
request["query_string"] = filtered_qs
else:
request["query_string"] = query_string
if query_string:
filtered_qs = _apply_key_value_collection_filtering(
items=query_string,
behaviour=data_collection["url_query_params"],
)
if filtered_qs:
request["query_string"] = filtered_qs

if "headers" in aws_event:
request["headers"] = _filter_headers(aws_event["headers"])

client_options = sentry_sdk.get_client().options
if has_data_collection_enabled(client_options):
if client_options["data_collection"]["user_info"]:
extracted_user = _get_user_from_event(aws_event)
if extracted_user:
user_info = sentry_event.setdefault("user", {})
for key, value in extracted_user.items():
user_info.setdefault(key, value)

if "incoming_request" in client_options["data_collection"]["http_bodies"]:
if "body" in aws_event:
request["data"] = aws_event.get("body", "")

elif should_send_default_pii():
if data_collection["user_info"]:
extracted_user = _get_user_from_event(aws_event)
if extracted_user:
user_info = sentry_event.setdefault("user", {})
for key, value in extracted_user.items():
user_info.setdefault(key, value)

if "incoming_request" in data_collection["http_bodies"]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default config now sends request bodies

High Severity

Dropping the send_default_pii fallback makes raw request bodies attach whenever http_bodies includes incoming_request. The mapped default always includes that type, so layer and other unset-data_collection users now send unstructured bodies that the previous path marked as removed. Those payloads can contain credentials and other PII.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7fbc174. Configure here.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's intended on the major

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I was a bit confused. It's also flagging this on the other PR's: #7637 (comment)

if "body" in aws_event:
request["data"] = aws_event.get("body", "")
else:
if aws_event.get("body", None):
# Unfortunately couldn't find a way to get structured body from AWS
# event. Meaning every body is unstructured to us.
request["data"] = AnnotatedValue.removed_because_raw_data()
elif aws_event.get("body", None):
# Unfortunately couldn't find a way to get structured body from AWS
# event. Meaning every body is unstructured to us.
request["data"] = AnnotatedValue.removed_because_raw_data()

sentry_event["request"] = deepcopy(request)

Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

sentry_sdk.init(
dsn=os.environ.get("SENTRY_DSN"),
data_collection={},
traces_sample_rate=1.0,
integrations=[AwsLambdaIntegration()],
)
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

sentry_sdk.init(
dsn=os.environ.get("SENTRY_DSN"),
data_collection={},
traces_sample_rate=None, # this is the default, just added for clarity
integrations=[AwsLambdaIntegration()],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

sentry_sdk.init(
dsn=os.environ.get("SENTRY_DSN"),
data_collection={},
traces_sample_rate=1.0,
integrations=[AwsLambdaIntegration()],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

sentry_sdk.init(
dsn=os.environ.get("SENTRY_DSN"),
data_collection={},
traces_sample_rate=1.0,
integrations=[AwsLambdaIntegration()],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

sentry_sdk.init(
dsn=os.environ.get("SENTRY_DSN"),
data_collection={},
traces_sample_rate=1.0,
integrations=[AwsLambdaIntegration(timeout_warning=True)],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def trace_sampler(sampling_context):

sentry_sdk.init(
dsn=os.environ.get("SENTRY_DSN"),
data_collection={},
traces_sample_rate=1.0,
traces_sampler=trace_sampler,
integrations=[AwsLambdaIntegration()],
Expand Down
51 changes: 5 additions & 46 deletions tests/integrations/aws_lambda/test_aws_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def test_non_dict_event(
assert segment_spans[0]["status"] == "error"


def test_request_data_with_send_default_pii_false(lambda_client, test_environment):
def test_request_data_with_default_data_collection(lambda_client, test_environment):
payload = b"""
{
"resource": "/asd",
Expand Down Expand Up @@ -290,8 +290,7 @@ def test_request_data_with_send_default_pii_false(lambda_client, test_environmen
attrs = segment_spans[0]["attributes"]

assert _get_span_attr(attrs, "http.request.method") == "GET"
# With send_default_pii=False (default for layer), query string is not included.
assert "url.query" not in attrs
assert _get_span_attr(attrs, "url.query") == "bonkers=true"


USER_INFO_PAYLOAD = b"""
Expand Down Expand Up @@ -827,7 +826,7 @@ def test_request_attributes(lambda_client, test_environment):
}

lambda_client.invoke(
FunctionName="BasicOkSpanStreamingPii",
FunctionName="BasicOkSpanStreamingDataCollection",
Payload=json.dumps(payload),
)
span_items = test_environment["server"].span_items
Expand All @@ -846,14 +845,14 @@ def test_request_attributes(lambda_client, test_environment):
_get_span_attr(attrs, "http.request.header.content-type") == "application/json"
)
assert _get_span_attr(attrs, "http.request.header.accept") == "text/html"
assert _get_span_attr(attrs, "faas.name") == "BasicOkSpanStreamingPii"
assert _get_span_attr(attrs, "faas.name") == "BasicOkSpanStreamingDataCollection"
assert _get_span_attr(attrs, "cloud.provider") == "aws"
assert _get_span_attr(attrs, "cloud.platform") == "aws_lambda"
assert _get_span_attr(attrs, "cloud.region") == "us-east-1"
assert _get_span_attr(attrs, "faas.version") == "$LATEST"
assert "faas.invocation_id" in attrs
assert _get_span_attr(attrs, "aws.log.group.names") == [
"aws/lambda/BasicOkSpanStreamingPii"
"aws/lambda/BasicOkSpanStreamingDataCollection"
]
assert _get_span_attr(attrs, "aws.log.stream.names") == ["$LATEST"]

Expand Down Expand Up @@ -888,46 +887,6 @@ def test_url_query_params_with_data_collection(lambda_client, test_environment):
)


def test_user_info_with_send_default_pii(lambda_client, test_environment):
payload = b"""
{
"resource": "/asd",
"path": "/asd",
"httpMethod": "GET",
"headers": {
"Host": "iwsz2c7uwi.execute-api.us-east-1.amazonaws.com",
"User-Agent": "custom",
"X-Forwarded-Proto": "https"
},
"queryStringParameters": {
"bonkers": "true"
},
"pathParameters": null,
"stageVariables": null,
"requestContext": {
"identity": {
"sourceIp": "213.47.147.207",
"userArn": "42"
}
},
"body": null,
"isBase64Encoded": false
}
"""

lambda_client.invoke(
FunctionName="BasicOkSpanStreamingPii",
Payload=payload,
)
span_items = test_environment["server"].span_items

segment_spans = [s for s in span_items if s.get("is_segment")]
assert len(segment_spans) == 1
attrs = segment_spans[0]["attributes"]

assert _get_span_attr(attrs, "user.id") == "42"


def test_user_info_with_data_collection_user_info_off(lambda_client, test_environment):
lambda_client.invoke(
FunctionName="BasicOkSpanStreamingDataCollectionUserInfoOff",
Expand Down
Loading