diff --git a/ddtrace/appsec/_asm_request_context.py b/ddtrace/appsec/_asm_request_context.py index d445e580653..9811e385309 100644 --- a/ddtrace/appsec/_asm_request_context.py +++ b/ddtrace/appsec/_asm_request_context.py @@ -151,7 +151,7 @@ def finalise(self): callbacks = GLOBAL_CALLBACKS.get(_CONTEXT_CALL, []) if env.must_call_globals else [] env.must_call_globals = False if env is not None and env.callbacks is not None and env.callbacks.get(_CONTEXT_CALL): - callbacks += env.callbacks.get(_CONTEXT_CALL) + callbacks = callbacks + env.callbacks.get(_CONTEXT_CALL) if callbacks: if env is not None: for function in callbacks: diff --git a/releasenotes/notes/fix_incident_25768-043ae458e46c9620.yaml b/releasenotes/notes/fix_incident_25768-043ae458e46c9620.yaml new file mode 100644 index 00000000000..ab89ec6dded --- /dev/null +++ b/releasenotes/notes/fix_incident_25768-043ae458e46c9620.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + ASM: This fix resolves an issue with Flask instrumentation causing CPU leak with ASM, + API Security and Telemetry enabled. diff --git a/tests/appsec/contrib_appsec/utils.py b/tests/appsec/contrib_appsec/utils.py index 46e6ee13b0a..e05901c12c0 100644 --- a/tests/appsec/contrib_appsec/utils.py +++ b/tests/appsec/contrib_appsec/utils.py @@ -1037,6 +1037,25 @@ def test_multiple_service_name(self, interface): else: raise AssertionError("extra service not found") + def test_global_callback_list_length(self, interface): + from ddtrace.appsec import _asm_request_context + + with override_global_config( + dict( + _asm_enabled=True, + _api_security_enabled=True, + _telemetry_enabled=True, + ) + ): + self.update_tracer(interface) + assert ddtrace.config._remote_config_enabled + for _ in range(20): + response = interface.client.get("/new_service/awesome_test") + assert self.status(response) == 200 + assert self.body(response) == "awesome_test" + # only two global callbacks are expected for API Security and Nested Events + assert len(_asm_request_context.GLOBAL_CALLBACKS.get(_asm_request_context._CONTEXT_CALL, [])) == 2 + @contextmanager def test_tracer():