Skip to content

Commit 3a5a7f8

Browse files
authored
Fix NullPointerException in ObjectIntrospection (#9878)
What Does This Do Added a null guard in ObjectIntrospection.checkStringLength so Jackson string values that resolve to null no longer trigger a NullPointerException during AppSec object conversion
1 parent 74cc32f commit 3a5a7f8

File tree

3 files changed

+116
-0
lines changed

3 files changed

+116
-0
lines changed

dd-java-agent/appsec/src/main/java/com/datadog/appsec/event/data/ObjectIntrospection.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,9 @@ private static boolean setAccessible(Field field) {
345345
}
346346

347347
private static String checkStringLength(final String str, final State state) {
348+
if (str == null) {
349+
return null;
350+
}
348351
if (str.length() > MAX_STRING_SIZE) {
349352
state.stringTooLong = true;
350353
return str.substring(0, MAX_STRING_SIZE);

dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/event/data/ObjectIntrospectionSpecification.groovy

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.datadog.appsec.event.data
22

33
import com.datadog.appsec.gateway.AppSecRequestContext
44
import com.fasterxml.jackson.databind.ObjectMapper
5+
import com.fasterxml.jackson.databind.node.NullTextJsonNode
56
import datadog.trace.api.telemetry.WafMetricCollector
67
import datadog.trace.test.util.DDSpecification
78
import groovy.json.JsonBuilder
@@ -354,6 +355,14 @@ class ObjectIntrospectionSpecification extends DDSpecification {
354355
MAPPER.readTree('{"key": "value"}') || [key: 'value']
355356
}
356357

358+
void 'jackson text nodes with null textual value are handled gracefully'() {
359+
given:
360+
def node = new NullTextJsonNode()
361+
362+
expect:
363+
convert(node, ctx) == null
364+
}
365+
357366
void 'jackson nested structures'() {
358367
when:
359368
final result = convert(input, ctx)
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package com.fasterxml.jackson.databind.node
2+
3+
import com.fasterxml.jackson.core.JsonGenerator
4+
import com.fasterxml.jackson.core.JsonPointer
5+
import com.fasterxml.jackson.core.JsonToken
6+
import com.fasterxml.jackson.databind.JsonNode
7+
import com.fasterxml.jackson.databind.SerializerProvider
8+
import com.fasterxml.jackson.databind.jsontype.TypeSerializer
9+
10+
class NullTextJsonNode extends BaseJsonNode {
11+
@Override
12+
JsonNodeType getNodeType() {
13+
return JsonNodeType.STRING
14+
}
15+
16+
@Override
17+
String textValue() {
18+
return null
19+
}
20+
21+
@Override
22+
JsonToken asToken() {
23+
return JsonToken.VALUE_STRING
24+
}
25+
26+
@Override
27+
void serialize(JsonGenerator gen, SerializerProvider serializers) throws IOException {
28+
gen.writeNull()
29+
}
30+
31+
@Override
32+
JsonNode deepCopy() {
33+
return this
34+
}
35+
36+
@Override
37+
String asText() {
38+
return null
39+
}
40+
41+
@Override
42+
boolean equals(Object o) {
43+
if (this.is(o)) {
44+
return true
45+
}
46+
return o != null && getClass() == o.class
47+
}
48+
49+
@Override
50+
int hashCode() {
51+
return getClass().hashCode()
52+
}
53+
54+
@Override
55+
void serializeWithType(JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException {
56+
gen.writeNull()
57+
}
58+
59+
@Override
60+
JsonNode get(int index) {
61+
return null
62+
}
63+
64+
@Override
65+
JsonNode path(String fieldName) {
66+
return MissingNode.getInstance()
67+
}
68+
69+
@Override
70+
JsonNode path(int index) {
71+
return MissingNode.getInstance()
72+
}
73+
74+
@Override
75+
@SuppressWarnings('MethodName') // Inherited from Jackson's BaseJsonNode
76+
protected JsonNode _at(JsonPointer ptr) {
77+
return MissingNode.getInstance()
78+
}
79+
80+
@Override
81+
JsonNode findValue(String fieldName) {
82+
return null
83+
}
84+
85+
@Override
86+
JsonNode findParent(String fieldName) {
87+
return null
88+
}
89+
90+
@Override
91+
List<JsonNode> findValues(String fieldName, List<JsonNode> foundSoFar) {
92+
return foundSoFar != null ? foundSoFar : new ArrayList<JsonNode>()
93+
}
94+
95+
@Override
96+
List<String> findValuesAsText(String fieldName, List<String> foundSoFar) {
97+
return foundSoFar != null ? foundSoFar : new ArrayList<String>()
98+
}
99+
100+
@Override
101+
List<JsonNode> findParents(String fieldName, List<JsonNode> foundSoFar) {
102+
return foundSoFar != null ? foundSoFar : new ArrayList<JsonNode>()
103+
}
104+
}

0 commit comments

Comments
 (0)