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
32 changes: 27 additions & 5 deletions ddtrace/appsec/_iast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def wrapped_function(wrapped, instance, args, kwargs):
_IAST_TO_BE_LOADED = True
_iast_propagation_enabled = False
_fork_handler_registered = False
_iast_in_pytest_mode = False


def _disable_iast_after_fork():
Expand Down Expand Up @@ -87,6 +88,15 @@ def _disable_iast_after_fork():
from ddtrace.appsec._iast._iast_request_context_base import is_iast_request_enabled
from ddtrace.appsec._iast._taint_tracking._context import clear_all_request_context_slots

# In pytest mode, always disable IAST in child processes to avoid segfaults
# when tests create multiprocesses (e.g., for testing fork behavior)
if _iast_in_pytest_mode:
log.debug("IAST fork handler: Pytest mode detected, disabling IAST in child process")
clear_all_request_context_slots()
IAST_CONTEXT.set(None)
asm_config._iast_enabled = False
return

if not is_iast_request_enabled():
# No active context - this is an early fork (web framework worker)
# IAST can be safely initialized fresh in this child process
Expand Down Expand Up @@ -168,6 +178,7 @@ def enable_iast_propagation():
"""Add IAST AST patching in the ModuleWatchdog"""
# DEV: These imports are here to avoid _ast.ast_patching import in the top level
# because they are slow and affect serverless startup time

if asm_config._iast_propagation_enabled:
from ddtrace.appsec._iast._ast.ast_patching import _should_iast_patch
from ddtrace.appsec._iast._loader import _exec_iast_patched_module
Expand All @@ -183,19 +194,30 @@ def enable_iast_propagation():


def _iast_pytest_activation():
global _iast_propagation_enabled
if _iast_propagation_enabled:
"""Configure IAST settings for pytest execution.

This function sets up IAST configuration but does NOT create a request context.
Request contexts should be created per-test or per-request to avoid threading issues.

Also sets a global flag to indicate we're in pytest mode, which ensures IAST is
disabled in forked child processes to prevent segfaults when tests use multiprocessing.
"""
global _iast_in_pytest_mode

if not asm_config._iast_enabled:
return
os.environ["DD_IAST_ENABLED"] = os.environ.get("DD_IAST_ENABLED") or "1"

# Mark that we're running in pytest mode
# This flag is checked by the fork handler to disable IAST in child processes
_iast_in_pytest_mode = True

os.environ["DD_IAST_REQUEST_SAMPLING"] = os.environ.get("DD_IAST_REQUEST_SAMPLING") or "100.0"
os.environ["_DD_APPSEC_DEDUPLICATION_ENABLED"] = os.environ.get("_DD_APPSEC_DEDUPLICATION_ENABLED") or "false"
os.environ["DD_IAST_VULNERABILITIES_PER_REQUEST"] = os.environ.get("DD_IAST_VULNERABILITIES_PER_REQUEST") or "1000"
os.environ["DD_IAST_MAX_CONCURRENT_REQUESTS"] = os.environ.get("DD_IAST_MAX_CONCURRENT_REQUESTS") or "1000"

asm_config._iast_request_sampling = 100.0
asm_config._deduplication_enabled = False
asm_config._iast_max_vulnerabilities_per_requests = 1000
asm_config._iast_max_concurrent_requests = 1000
oce.reconfigure()


Expand Down
2 changes: 2 additions & 0 deletions ddtrace/settings/asm.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ class ASMConfig(DDConfig):
+ r"ey[I-L][\w=-]+\.ey[I-L][\w=-]+(\.[\w.+\/=-]+)?|[\-]{5}BEGIN[a-z\s]+PRIVATE\sKEY"
+ r"[\-]{5}[^\-]+[\-]{5}END[a-z\s]+PRIVATE\sKEY|ssh-rsa\s*[a-z0-9\/\.+]{100,}",
)
# We never use `asm_config._iast_max_concurrent_requests` directly,
# but we define it so it can be reported through telemetry, since it’s used from the C files.
_iast_max_concurrent_requests = DDConfig.var(
int,
IAST.DD_IAST_MAX_CONCURRENT_REQUESTS,
Expand Down
8 changes: 1 addition & 7 deletions tests/appsec/iast/aspects/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@
@pytest.fixture(autouse=True)
def iast_request():
with override_global_config(
dict(
_iast_enabled=True,
_iast_is_testing=True,
_iast_deduplication_enabled=False,
_iast_request_sampling=100.0,
_iast_max_concurrent_requests=100,
)
dict(_iast_enabled=True, _iast_is_testing=True, _iast_deduplication_enabled=False, _iast_request_sampling=100.0)
):
context_id = _start_iast_context_and_oce()
assert context_id is not None
Expand Down
8 changes: 1 addition & 7 deletions tests/appsec/iast/taint_tracking/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,7 @@
@pytest.fixture(autouse=True)
def iast_request():
with override_global_config(
dict(
_iast_enabled=True,
_iast_is_testing=True,
_iast_deduplication_enabled=False,
_iast_request_sampling=100.0,
_iast_max_concurrent_requests=100,
)
dict(_iast_enabled=True, _iast_is_testing=True, _iast_deduplication_enabled=False, _iast_request_sampling=100.0)
):
assert debug_context_array_size() == 2
_start_iast_context_and_oce()
Expand Down
Loading