Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b381cb3
chore(iast): finer-grained header injection for django
avara1986 May 30, 2025
44a43fc
chore(iast): finer-grained header injection for django
avara1986 May 30, 2025
1c64d3f
Merge branch 'main' into avara1986/APPSEC-57163-header_injection
avara1986 Jun 2, 2025
b74642b
chore(iast): finer-grained header injection for django
avara1986 Jun 2, 2025
5e97b1f
chore(iast): finer-grained header injection for django
avara1986 Jun 2, 2025
f9d7beb
chore(iast): finer-grained header injection for django
avara1986 Jun 2, 2025
e6301f5
chore(iast): finer-grained header injection for django
avara1986 Jun 2, 2025
ee6f01a
chore(iast): finer-grained header injection for django
avara1986 Jun 2, 2025
e0befa5
chore(iast): finer-grained header injection for django
avara1986 Jun 2, 2025
e990335
chore(iast): finer-grained header injection for django
avara1986 Jun 3, 2025
bf455a2
chore(iast): finer-grained header injection for django
avara1986 Jun 3, 2025
1d01278
chore(iast): finer-grained header injection for django
avara1986 Jun 3, 2025
451ebe6
Merge branch 'main' into avara1986/APPSEC-57163-header_injection
avara1986 Jun 3, 2025
285e508
chore(iast): finer-grained header injection for django
avara1986 Jun 3, 2025
cdfa4a1
chore(iast): finer-grained header injection for django
avara1986 Jun 3, 2025
5c11936
chore(iast): finer-grained header injection for django
avara1986 Jun 3, 2025
dbbe796
Merge branch 'main' into avara1986/APPSEC-57163-header_injection
avara1986 Jun 4, 2025
fd23336
chore(iast): finer-grained header injection for django
avara1986 Jun 4, 2025
23034eb
chore(iast): finer-grained header injection for django
avara1986 Jun 4, 2025
73d01f7
chore(iast): finer-grained header injection for django
avara1986 Jun 4, 2025
da424c1
chore(iast): finer-grained header injection for django
avara1986 Jun 4, 2025
28c409a
chore(iast): finer-grained header injection for django
avara1986 Jun 4, 2025
b0a339c
chore(iast): finer-grained header injection for django
avara1986 Jun 4, 2025
8cc1bc0
chore(iast): finer-grained header injection for django
avara1986 Jun 4, 2025
aa6ee10
chore(iast): finer-grained header injection for django
avara1986 Jun 4, 2025
30e9531
chore(iast): finer-grained header injection for django
avara1986 Jun 4, 2025
f0d9d96
chore(iast): finer-grained header injection for django
avara1986 Jun 4, 2025
f695972
Merge branch 'main' into avara1986/APPSEC-57163-header_injection
avara1986 Jun 4, 2025
df18e65
Merge branch 'main' into avara1986/APPSEC-57163-header_injection
avara1986 Jun 5, 2025
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
8 changes: 4 additions & 4 deletions .github/workflows/system-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
persist-credentials: false
repository: 'DataDog/system-tests'
# Automatically managed, use scripts/update-system-tests-version to update
ref: 'bc5ac8df80c981de47ad258e066c26e2fc5ff4ee'
ref: '3b3df04b753484a73a4b78fcdd95d5076da87602'

- name: Build agent
run: ./build.sh -i agent
Expand Down Expand Up @@ -69,7 +69,7 @@ jobs:
persist-credentials: false
repository: 'DataDog/system-tests'
# Automatically managed, use scripts/update-system-tests-version to update
ref: 'bc5ac8df80c981de47ad258e066c26e2fc5ff4ee'
ref: '3b3df04b753484a73a4b78fcdd95d5076da87602'

- name: Checkout dd-trace-py
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Expand Down Expand Up @@ -123,7 +123,7 @@ jobs:
persist-credentials: false
repository: 'DataDog/system-tests'
# Automatically managed, use scripts/update-system-tests-version to update
ref: 'bc5ac8df80c981de47ad258e066c26e2fc5ff4ee'
ref: '3b3df04b753484a73a4b78fcdd95d5076da87602'

- name: Build runner
uses: ./.github/actions/install_runner
Expand Down Expand Up @@ -310,7 +310,7 @@ jobs:
persist-credentials: false
repository: 'DataDog/system-tests'
# Automatically managed, use scripts/update-system-tests-version to update
ref: 'bc5ac8df80c981de47ad258e066c26e2fc5ff4ee'
ref: '3b3df04b753484a73a4b78fcdd95d5076da87602'
- name: Checkout dd-trace-py
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
Expand Down
5 changes: 3 additions & 2 deletions ddtrace/appsec/_iast/_ast/iastpatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ static size_t cached_packages_count = 0;

/* Static Lists */
static const char* static_allowlist[] = {
"jinja2.", "pygments.", "multipart.", "sqlalchemy.", "python_multipart.", "attrs.", "jsonschema.",
"s3fs.", "mysql.", "pymysql.", "markupsafe.", "werkzeug.utils.", "langchain.", "langchain_core."
"jinja2.", "pygments.", "multipart.", "sqlalchemy.", "python_multipart.",
"attrs.", "jsonschema.", "s3fs.", "mysql.", "pymysql.",
"markupsafe.", "werkzeug.utils.", "langchain.", "langchain_core.", "django.http.response"
};
static const size_t static_allowlist_count = sizeof(static_allowlist) / sizeof(static_allowlist[0]);

Expand Down
4 changes: 4 additions & 0 deletions ddtrace/appsec/_iast/_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,12 @@ def _on_django_func_wrapped(fn_args, fn_kwargs, first_arg_expected_type, *_):
)
except AttributeError:
log.debug("IAST can't set attribute http_req._body", exc_info=True)
# This condition is only for testing purposes.
# In real applications, http_req.body is typically a property that can be set.
# Here we check if it's not a property to handle test cases where body is directly assigned.
elif (
getattr(http_req, "body", None) is not None
and not isinstance(getattr(http_req, "body", None), property)
and len(getattr(http_req, "body", None)) > 0
and not is_pyobject_tainted(getattr(http_req, "body", None))
):
Expand Down
15 changes: 15 additions & 0 deletions ddtrace/appsec/_iast/_patch_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from ddtrace.appsec._iast.secure_marks.sanitizers import path_traversal_sanitizer
from ddtrace.appsec._iast.secure_marks.sanitizers import sqli_sanitizer
from ddtrace.appsec._iast.secure_marks.sanitizers import xss_sanitizer
from ddtrace.appsec._iast.secure_marks.validators import header_injection_validator
from ddtrace.appsec._iast.secure_marks.validators import ssrf_validator
from ddtrace.appsec._iast.secure_marks.validators import unvalidated_redirect_validator

Expand Down Expand Up @@ -70,6 +71,20 @@ def patch_iast(patch_modules=IAST_PATCH):
)
)

# Header Injection validators
# Header injection for > Django 3.2
when_imported("django.http.response")(
lambda _: try_wrap_function_wrapper(
"django.http.response", "ResponseHeaders._convert_to_charset", header_injection_validator
)
)
# Header injection for <= Django 2.2
when_imported("django.http.response")(
lambda _: try_wrap_function_wrapper(
"django.http.response", "HttpResponseBase._convert_to_charset", header_injection_validator
)
)

# Unvalidated Redirect validators
when_imported("django.utils.http")(
lambda _: try_wrap_function_wrapper(
Expand Down
3 changes: 2 additions & 1 deletion ddtrace/appsec/_iast/_stacktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ _is_ddtrace_filename(const char* filename)
static inline bool
_is_site_packages_filename(const char* filename)
{
const bool res = filename && PURELIB_PATH && strncmp(filename, PURELIB_PATH, PURELIB_PATH_LEN) == 0;
const bool res = filename && PURELIB_PATH &&
(strstr(filename, "site-packages/") || strncmp(filename, PURELIB_PATH, PURELIB_PATH_LEN) == 0);
return res;
}

Expand Down
4 changes: 4 additions & 0 deletions ddtrace/appsec/_iast/secure_marks/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ def unvalidated_redirect_validator(wrapped: Callable, instance: Any, args: Seque
return create_validator(VulnerabilityType.UNVALIDATED_REDIRECT, wrapped, instance, args, kwargs)


def header_injection_validator(wrapped: Callable, instance: Any, args: Sequence, kwargs: dict) -> bool:
return create_validator(VulnerabilityType.HEADER_INJECTION, wrapped, instance, args, kwargs)


def ssrf_validator(wrapped: Callable, instance: Any, args: Sequence, kwargs: dict) -> bool:
"""Validator for ssrf functions.

Expand Down
Loading
Loading