From a91a22830f5df12d68eee69d68e6dbc92c35008a Mon Sep 17 00:00:00 2001 From: Alberto Vara Date: Fri, 7 Feb 2025 13:04:21 +0100 Subject: [PATCH] chore(iast): xss vulnerability for jinja2 (#12238) Even when starting the application with `ddtrace-run ddtrace-run`, `jinja2.FILTERS` is created before this patch function executes. Therefore, we update the in-memory object with the newly patched version. ## Checklist - [x] PR author has checked that all the criteria below are met - The PR description includes an overview of the change - The PR description articulates the motivation for the change - The change includes tests OR the PR description describes a testing strategy - The PR description notes risks associated with the change, if any - Newly-added code is easy to change - The change follows the [library release note guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html) - The change includes or references documentation updates if necessary - Backport labels are set (if [applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)) ## Reviewer Checklist - [x] Reviewer has checked that all the criteria below are met - Title is accurate - All changes are related to the pull request's stated goal - Avoids breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes - Testing strategy adequately addresses listed risks - Newly-added code is easy to change - Release note makes sense to a user of the library - If necessary, author has acknowledged and discussed the performance implications of this PR as reported in the benchmarks PR comment - Backport labels are set in a manner that is consistent with the [release branch maintenance policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting) (cherry picked from commit a8dfadf8a3bb563b39ebc1600c6cf78aa7685e98) --- ddtrace/appsec/_iast/taint_sinks/xss.py | 10 +++++++++- .../fastapi_tests/test_fastapi_appsec_iast.py | 4 ---- .../appsec/integrations/flask_tests/test_iast_flask.py | 4 ---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ddtrace/appsec/_iast/taint_sinks/xss.py b/ddtrace/appsec/_iast/taint_sinks/xss.py index 6f7d263f7c2..73350faac44 100644 --- a/ddtrace/appsec/_iast/taint_sinks/xss.py +++ b/ddtrace/appsec/_iast/taint_sinks/xss.py @@ -64,7 +64,15 @@ def patch(): ) _set_metric_iast_instrumented_sink(VULN_XSS) - _set_metric_iast_instrumented_sink(VULN_XSS) + # Even when starting the application with `ddtrace-run ddtrace-run`, `jinja2.FILTERS` is created before this patch + # function executes. Therefore, we update the in-memory object with the newly patched version. + try: + from jinja2.filters import FILTERS + from jinja2.filters import do_mark_safe + + FILTERS["safe"] = do_mark_safe + except (ImportError, KeyError): + pass def unpatch(): diff --git a/tests/appsec/integrations/fastapi_tests/test_fastapi_appsec_iast.py b/tests/appsec/integrations/fastapi_tests/test_fastapi_appsec_iast.py index 07d8e1c9dc6..ee0b4e041d1 100644 --- a/tests/appsec/integrations/fastapi_tests/test_fastapi_appsec_iast.py +++ b/tests/appsec/integrations/fastapi_tests/test_fastapi_appsec_iast.py @@ -1003,10 +1003,6 @@ async def test_route(request: Request): with override_global_config(dict(_iast_enabled=True, _iast_request_sampling=100.0)): patch_iast({"xss": True}) - from jinja2.filters import FILTERS - from jinja2.filters import do_mark_safe - - FILTERS["safe"] = do_mark_safe _aux_appsec_prepare_tracer(tracer) resp = client.get( "/index.html?iast_queryparam=test1234", diff --git a/tests/appsec/integrations/flask_tests/test_iast_flask.py b/tests/appsec/integrations/flask_tests/test_iast_flask.py index 0d8f7c5b4ad..e84aaf3e196 100644 --- a/tests/appsec/integrations/flask_tests/test_iast_flask.py +++ b/tests/appsec/integrations/flask_tests/test_iast_flask.py @@ -51,10 +51,6 @@ def setUp(self): patch_header_injection() patch_xss_injection() patch_json() - from jinja2.filters import FILTERS - from jinja2.filters import do_mark_safe - - FILTERS["safe"] = do_mark_safe super(FlaskAppSecIASTEnabledTestCase, self).setUp() self.tracer._configure(api_version="v0.4", appsec_enabled=True, iast_enabled=True) oce.reconfigure()