|
| 1 | +from typing import Text |
| 2 | + |
| 3 | +from ddtrace.appsec._common_module_patches import try_unwrap |
| 4 | +from ddtrace.appsec._constants import IAST_SPAN_TAGS |
| 5 | +from ddtrace.appsec._iast import oce |
| 6 | +from ddtrace.appsec._iast._iast_request_context import is_iast_request_enabled |
| 7 | +from ddtrace.appsec._iast._metrics import _set_metric_iast_executed_sink |
| 8 | +from ddtrace.appsec._iast._metrics import _set_metric_iast_instrumented_sink |
| 9 | +from ddtrace.appsec._iast._metrics import increment_iast_span_metric |
| 10 | +from ddtrace.appsec._iast._patch import set_and_check_module_is_patched |
| 11 | +from ddtrace.appsec._iast._patch import set_module_unpatched |
| 12 | +from ddtrace.appsec._iast._patch import try_wrap_function_wrapper |
| 13 | +from ddtrace.appsec._iast._taint_tracking._taint_objects import is_pyobject_tainted |
| 14 | +from ddtrace.appsec._iast.constants import VULN_XSS |
| 15 | +from ddtrace.appsec._iast.taint_sinks._base import VulnerabilityBase |
| 16 | +from ddtrace.internal.logger import get_logger |
| 17 | +from ddtrace.settings.asm import config as asm_config |
| 18 | + |
| 19 | + |
| 20 | +log = get_logger(__name__) |
| 21 | + |
| 22 | + |
| 23 | +@oce.register |
| 24 | +class XSS(VulnerabilityBase): |
| 25 | + vulnerability_type = VULN_XSS |
| 26 | + |
| 27 | + |
| 28 | +def get_version() -> Text: |
| 29 | + return "" |
| 30 | + |
| 31 | + |
| 32 | +def patch(): |
| 33 | + if not asm_config._iast_enabled: |
| 34 | + return |
| 35 | + |
| 36 | + if not set_and_check_module_is_patched("flask", default_attr="_datadog_xss_patch"): |
| 37 | + return |
| 38 | + if not set_and_check_module_is_patched("django", default_attr="_datadog_xss_patch"): |
| 39 | + return |
| 40 | + if not set_and_check_module_is_patched("fastapi", default_attr="_datadog_xss_patch"): |
| 41 | + return |
| 42 | + |
| 43 | + try_wrap_function_wrapper( |
| 44 | + "django.utils.safestring", |
| 45 | + "mark_safe", |
| 46 | + _iast_django_xss, |
| 47 | + ) |
| 48 | + |
| 49 | + try_wrap_function_wrapper( |
| 50 | + "django.template.defaultfilters", |
| 51 | + "mark_safe", |
| 52 | + _iast_django_xss, |
| 53 | + ) |
| 54 | + |
| 55 | + _set_metric_iast_instrumented_sink(VULN_XSS) |
| 56 | + |
| 57 | + |
| 58 | +def unpatch(): |
| 59 | + try_unwrap("django.utils.safestring", "mark_safe") |
| 60 | + try_unwrap("django.template.defaultfilters", "mark_safe") |
| 61 | + |
| 62 | + set_module_unpatched("flask", default_attr="_datadog_xss_patch") |
| 63 | + set_module_unpatched("django", default_attr="_datadog_xss_patch") |
| 64 | + set_module_unpatched("fastapi", default_attr="_datadog_xss_patch") |
| 65 | + |
| 66 | + |
| 67 | +def _iast_django_xss(wrapped, instance, args, kwargs): |
| 68 | + if args and len(args) >= 1: |
| 69 | + _iast_report_xss(args[0]) |
| 70 | + return wrapped(*args, **kwargs) |
| 71 | + |
| 72 | + |
| 73 | +def _iast_report_xss(code_string: Text): |
| 74 | + increment_iast_span_metric(IAST_SPAN_TAGS.TELEMETRY_EXECUTED_SINK, XSS.vulnerability_type) |
| 75 | + _set_metric_iast_executed_sink(XSS.vulnerability_type) |
| 76 | + if is_iast_request_enabled(): |
| 77 | + if is_pyobject_tainted(code_string): |
| 78 | + XSS.report(evidence_value=code_string) |
0 commit comments