Skip to content

Commit c6833f9

Browse files
authored
fix(iast): incorrectly named as class_name (#13299)
IAST: Fix field naming for class in vulnerability location reporting Fixed: The field representing the class name in IAST vulnerability location reporting was previously incorrectly named as class_name in the codebase, but serialized as class in the output dictionary. This PR standardizes the naming and ensures that the correct field (class) is used in the output, improving consistency and compatibility with expected IAST report formats. Impact: This change affects the structure of IAST vulnerability reports, making them more accurate and aligned with the expected schema. There are no breaking changes to the API, but consumers of the IAST report output will now see the correct field name. APPSEC-57497 ## 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)
1 parent 24a7805 commit c6833f9

File tree

14 files changed

+67
-38
lines changed

14 files changed

+67
-38
lines changed

ddtrace/appsec/_iast/reporter.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def __eq__(self, other):
6464

6565

6666
@dataclasses.dataclass(unsafe_hash=True)
67-
class Location(NotNoneDictable):
67+
class Location:
6868
spanId: int = dataclasses.field(compare=False, hash=False, repr=False)
6969
path: Optional[str] = None
7070
line: Optional[int] = None
@@ -74,9 +74,23 @@ class Location(NotNoneDictable):
7474
def __repr__(self):
7575
return f"Location(path='{self.path}', line={self.line})"
7676

77+
def _to_dict(self):
78+
result = {}
79+
if self.spanId is not None:
80+
result["spanId"] = self.spanId
81+
if self.path is not None:
82+
result["path"] = self.path
83+
if self.line is not None:
84+
result["line"] = self.line
85+
if self.method is not None:
86+
result["method"] = self.method
87+
if self.class_name is not None:
88+
result["class"] = self.class_name
89+
return result
90+
7791

7892
@dataclasses.dataclass(unsafe_hash=True)
79-
class Vulnerability(NotNoneDictable):
93+
class Vulnerability:
8094
type: str
8195
evidence: Evidence
8296
location: Location
@@ -97,6 +111,17 @@ def __post_init__(self):
97111
def __repr__(self):
98112
return f"Vulnerability(type='{self.type}', location={self.location})"
99113

114+
def _to_dict(self):
115+
to_dict = {
116+
"type": self.type,
117+
"evidence": self.evidence._to_dict(),
118+
"location": self.location._to_dict(),
119+
"hash": self.hash,
120+
}
121+
if self.stackId:
122+
to_dict["stackId"] = self.stackId
123+
return to_dict
124+
100125

101126
@dataclasses.dataclass
102127
class Source(NotNoneDictable):
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
fixes:
3+
- |
4+
Code Security: The field representing the class name in IAST vulnerability location reporting was previously
5+
incorrectly named as class_name. This fix standardizes the naming and ensures that the correct field (class).

tests/appsec/iast/taint_sinks/test_command_injection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def _assert_vulnerability(label, value_parts=None, source_name="", check_value=F
5656
assert vulnerability["location"]["path"] == FIXTURES_PATH
5757
assert vulnerability["location"]["line"] == line
5858
assert vulnerability["location"]["method"] == function_name
59-
assert vulnerability["location"]["class_name"] == class_name
59+
assert vulnerability["location"]["class"] == class_name
6060
assert vulnerability["hash"] == hash_value
6161

6262

tests/appsec/iast/taint_sinks/test_header_injection_redacted.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def test_header_injection_redact_excluded(header_name, header_value, iast_contex
4141
{
4242
"evidence": {"valueParts": [{"value": header_name + ": "}, {"source": 0, "value": header_value}]},
4343
"hash": ANY,
44-
"location": {"line": ANY, "path": "foobar.py", "spanId": ANY, "method": ANY, "class_name": ANY},
44+
"location": {"line": ANY, "path": "foobar.py", "spanId": ANY, "method": ANY, "class": ANY},
4545
"type": VULN_HEADER_INJECTION,
4646
}
4747
],
@@ -85,7 +85,7 @@ def test_common_django_header_injection_redact(header_name, header_value, value_
8585
{
8686
"evidence": {"valueParts": value_part},
8787
"hash": ANY,
88-
"location": {"line": ANY, "path": "foobar.py", "spanId": ANY, "method": ANY, "class_name": ANY},
88+
"location": {"line": ANY, "path": "foobar.py", "spanId": ANY, "method": ANY, "class": ANY},
8989
"type": VULN_HEADER_INJECTION,
9090
}
9191
],

tests/appsec/iast/taint_sinks/test_path_traversal.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def test_path_traversal(module, function, iast_context_defaults):
129129
assert vulnerability["location"]["path"] == FIXTURES_PATH
130130
assert vulnerability["location"]["line"] == line
131131
assert vulnerability["location"]["method"] == path
132-
assert vulnerability["location"]["class_name"] == ""
132+
assert vulnerability["location"]["class"] == ""
133133
assert vulnerability["hash"] == hash_value
134134
assert vulnerability["evidence"]["valueParts"] == [{"source": 0, "value": file_path}]
135135
assert "value" not in vulnerability["evidence"].keys()

tests/appsec/iast/taint_sinks/test_path_traversal_redacted.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def test_path_traversal_redact_exclude(file_path, iast_context_defaults):
5151
{
5252
"evidence": {"valueParts": [{"source": 0, "value": file_path}]},
5353
"hash": ANY,
54-
"location": {"line": ANY, "path": "foobar.py", "spanId": ANY, "method": ANY, "class_name": ANY},
54+
"location": {"line": ANY, "path": "foobar.py", "spanId": ANY, "method": ANY, "class": ANY},
5555
"type": VULN_PATH_TRAVERSAL,
5656
}
5757
],
@@ -103,7 +103,7 @@ def test_path_traversal_redact_rel_paths(file_path, iast_context_defaults):
103103
{
104104
"evidence": {"valueParts": [{"source": 0, "value": file_path}]},
105105
"hash": ANY,
106-
"location": {"line": ANY, "path": "foobar.py", "spanId": ANY, "method": ANY, "class_name": ANY},
106+
"location": {"line": ANY, "path": "foobar.py", "spanId": ANY, "method": ANY, "class": ANY},
107107
"type": VULN_PATH_TRAVERSAL,
108108
}
109109
],
@@ -126,7 +126,7 @@ def test_path_traversal_redact_abs_paths(iast_context_defaults):
126126
{
127127
"evidence": {"valueParts": [{"source": 0, "value": file_path}]},
128128
"hash": ANY,
129-
"location": {"line": ANY, "path": "foobar.py", "spanId": ANY, "method": ANY, "class_name": ANY},
129+
"location": {"line": ANY, "path": "foobar.py", "spanId": ANY, "method": ANY, "class": ANY},
130130
"type": VULN_PATH_TRAVERSAL,
131131
}
132132
],

tests/appsec/iast/taint_sinks/test_ssrf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def _check_report(tainted_path, label):
5454
assert vulnerability["location"]["path"] == FIXTURES_PATH
5555
assert vulnerability["location"]["line"] == line
5656
assert vulnerability["location"]["method"] == label
57-
assert vulnerability["location"]["class_name"] == ""
57+
assert vulnerability["location"]["class"] == ""
5858
assert vulnerability["hash"] == hash_value
5959

6060

tests/appsec/iast/test_iast_propagation_path.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def _assert_vulnerability(data, value_parts, file_line_label):
2525
assert vulnerability["location"]["path"] == FIXTURES_PATH
2626
assert vulnerability["location"]["line"] == line
2727
assert vulnerability["location"]["method"] == file_line_label
28-
assert vulnerability["location"]["class_name"] == ""
28+
assert vulnerability["location"]["class"] == ""
2929
assert vulnerability["hash"] == hash_value
3030

3131

tests/appsec/integrations/django_tests/test_django_appsec_iast.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ def test_django_sqli_http_cookies_name(client, test_spans, tracer):
610610
assert vulnerability["location"]["path"] == TEST_FILE
611611
assert vulnerability["location"]["line"] == line
612612
assert vulnerability["location"]["method"] == "sqli_http_request_cookie_name"
613-
assert vulnerability["location"]["class_name"] == ""
613+
assert vulnerability["location"]["class"] == ""
614614
assert vulnerability["hash"] == hash_value
615615

616616

@@ -669,7 +669,7 @@ def test_django_sqli_http_cookies_value(client, test_spans, tracer):
669669
assert vulnerability["location"]["line"] == line
670670
assert vulnerability["location"]["path"] == TEST_FILE
671671
assert vulnerability["location"]["method"] == "sqli_http_request_cookie_value"
672-
assert vulnerability["location"]["class_name"] == ""
672+
assert vulnerability["location"]["class"] == ""
673673
assert vulnerability["hash"] == hash_value
674674

675675

tests/appsec/integrations/fastapi_tests/test_fastapi_appsec_iast.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ async def test_route(param_str):
684684
assert vulnerability["location"]["line"] == line
685685
assert vulnerability["location"]["path"] == TEST_FILE_PATH
686686
assert vulnerability["location"]["method"] == "test_route"
687-
assert vulnerability["location"]["class_name"] == ""
687+
assert vulnerability["location"]["class"] == ""
688688
assert vulnerability["hash"] == hash_value
689689

690690

@@ -946,7 +946,7 @@ async def header_injection(request: Request):
946946
assert vulnerability["location"]["line"] == line
947947
assert vulnerability["location"]["path"] == TEST_FILE_PATH
948948
assert vulnerability["location"]["method"] == "header_injection"
949-
assert vulnerability["location"]["class_name"] == ""
949+
assert vulnerability["location"]["class"] == ""
950950
assert vulnerability["location"]["spanId"]
951951

952952

0 commit comments

Comments
 (0)