@@ -23,6 +23,61 @@ class XMLDecoderReadObjectMethod extends Method {
2323 }
2424}
2525
26+ class ObjectMapperReadMethod extends Method {
27+ ObjectMapperReadMethod ( ) {
28+ this .getDeclaringType ( ) instanceof ObjectMapper and
29+ this .hasName ( [ "readValue" , "readValues" , "treeToValue" ] )
30+ }
31+ }
32+
33+ class ObjectMapper extends RefType {
34+ ObjectMapper ( ) { hasQualifiedName ( "com.fasterxml.jackson.databind" , "ObjectMapper" ) }
35+ }
36+
37+ class MapperBuilder extends RefType {
38+ MapperBuilder ( ) {
39+ hasQualifiedName ( "com.fasterxml.jackson.databind.cfg" , "MapperBuilder<JsonMapper,Builder>" )
40+ }
41+ }
42+
43+ class JsonFactory extends RefType {
44+ JsonFactory ( ) { hasQualifiedName ( "com.fasterxml.jackson.core" , "JsonFactory" ) }
45+ }
46+
47+ class JsonParser extends RefType {
48+ JsonParser ( ) { hasQualifiedName ( "com.fasterxml.jackson.core" , "JsonParser" ) }
49+ }
50+
51+ class EnableJacksonDefaultTyping extends MethodAccess {
52+ EnableJacksonDefaultTyping ( ) {
53+ this .getMethod ( ) .getDeclaringType ( ) instanceof ObjectMapper and
54+ this .getMethod ( ) .hasName ( "enableDefaultTyping" )
55+ }
56+ }
57+
58+ class ObjectMapperReadSink extends DataFlow:: ExprNode {
59+ ObjectMapperReadSink ( ) {
60+ exists ( MethodAccess ma | ma .getQualifier ( ) = this .asExpr ( ) |
61+ ma .getMethod ( ) instanceof ObjectMapperReadMethod
62+ )
63+ }
64+ }
65+
66+ class SetPolymorphicTypeValidatorSource extends DataFlow:: ExprNode {
67+ SetPolymorphicTypeValidatorSource ( ) {
68+ exists ( MethodAccess ma , Method m , Expr q | m = ma .getMethod ( ) and q = ma .getQualifier ( ) |
69+ (
70+ m .getDeclaringType ( ) instanceof ObjectMapper and
71+ m .hasName ( "setPolymorphicTypeValidator" )
72+ or
73+ m .getDeclaringType ( ) instanceof MapperBuilder and
74+ m .hasName ( "polymorphicTypeValidator" )
75+ ) and
76+ this .asExpr ( ) = [ q , q .( VarAccess ) .getVariable ( ) .getAnAccess ( ) ]
77+ )
78+ }
79+ }
80+
2681class SafeXStream extends DataFlow2:: Configuration {
2782 SafeXStream ( ) { this = "UnsafeDeserialization::SafeXStream" }
2883
@@ -114,6 +169,87 @@ class SafeKryo extends DataFlow2::Configuration {
114169 }
115170}
116171
172+ class EnabledJacksonDefaultTyping extends DataFlow2:: Configuration {
173+ EnabledJacksonDefaultTyping ( ) { this = "EnabledJacksonDefaultTyping" }
174+
175+ override predicate isSource ( DataFlow:: Node src ) {
176+ any ( EnableJacksonDefaultTyping ma ) .getQualifier ( ) .( VarAccess ) .getVariable ( ) .getAnAccess ( ) =
177+ src .asExpr ( )
178+ }
179+
180+ override predicate isSink ( DataFlow:: Node sink ) { sink instanceof ObjectMapperReadSink }
181+ }
182+
183+ class SafeObjectMapper extends DataFlow2:: Configuration {
184+ SafeObjectMapper ( ) { this = "SafeObjectMapper" }
185+
186+ override predicate isSource ( DataFlow:: Node src ) {
187+ src instanceof SetPolymorphicTypeValidatorSource
188+ }
189+
190+ override predicate isSink ( DataFlow:: Node sink ) { sink instanceof ObjectMapperReadSink }
191+
192+ /**
193+ * Holds if `fromNode` to `toNode` is a dataflow step
194+ * that configures or creates an `ObjectMapper` via a builder.
195+ */
196+ override predicate isAdditionalFlowStep ( DataFlow:: Node fromNode , DataFlow:: Node toNode ) {
197+ exists ( MethodAccess ma , Method m , Expr q | m = ma .getMethod ( ) and q = ma .getQualifier ( ) |
198+ m .getDeclaringType ( ) instanceof MapperBuilder and
199+ m .getReturnType ( )
200+ .( RefType )
201+ .hasQualifiedName ( "com.fasterxml.jackson.databind.json" ,
202+ [ "JsonMapper$Builder" , "JsonMapper" ] ) and
203+ fromNode .asExpr ( ) = [ q , q .( VarAccess ) .getVariable ( ) .getAnAccess ( ) ] and
204+ ma = toNode .asExpr ( )
205+ )
206+ }
207+ }
208+
209+ /**
210+ * Holds if `fromNode` to `toNode` is a dataflow step that creates a Jackson parser.
211+ */
212+ predicate createJacksonJsonParserStep ( DataFlow:: Node fromNode , DataFlow:: Node toNode ) {
213+ exists ( MethodAccess ma , Method m | m = ma .getMethod ( ) |
214+ ( m .getDeclaringType ( ) instanceof ObjectMapper or m .getDeclaringType ( ) instanceof JsonFactory ) and
215+ m .hasName ( "createParser" ) and
216+ ma .getArgument ( 0 ) = fromNode .asExpr ( ) and
217+ ma = toNode .asExpr ( )
218+ )
219+ }
220+
221+ /**
222+ * Holds if `fromNode` to `toNode` is a dataflow step that creates a Jackson `TreeNode`.
223+ */
224+ predicate createJacksonTreeNodeStep ( DataFlow:: Node fromNode , DataFlow:: Node toNode ) {
225+ exists ( MethodAccess ma , Method m | m = ma .getMethod ( ) |
226+ m .getDeclaringType ( ) instanceof ObjectMapper and
227+ m .hasName ( "readTree" ) and
228+ ma .getArgument ( 0 ) = fromNode .asExpr ( ) and
229+ ma = toNode .asExpr ( )
230+ )
231+ or
232+ exists ( MethodAccess ma , Method m | m = ma .getMethod ( ) |
233+ m .getDeclaringType ( ) instanceof JsonParser and
234+ m .hasName ( "readValueAsTree" ) and
235+ ma .getQualifier ( ) = fromNode .asExpr ( ) and
236+ ma = toNode .asExpr ( )
237+ )
238+ }
239+
240+ predicate hasJsonTypeInfoAnnotation ( RefType type ) {
241+ hasFieldWithJsonTypeAnnotation ( type .getASupertype * ( ) ) or
242+ hasFieldWithJsonTypeAnnotation ( type .getAField ( ) .getType ( ) )
243+ }
244+
245+ predicate hasFieldWithJsonTypeAnnotation ( RefType type ) {
246+ exists ( Annotation a |
247+ type .getAField ( ) .getAnAnnotation ( ) = a and
248+ a .getType ( ) .hasQualifiedName ( "com.fasterxml.jackson.annotation" , "JsonTypeInfo" ) and
249+ a .getValue ( "use" ) .( VarAccess ) .getVariable ( ) .hasName ( "CLASS" )
250+ )
251+ }
252+
117253predicate unsafeDeserialization ( MethodAccess ma , Expr sink ) {
118254 exists ( Method m | m = ma .getMethod ( ) |
119255 m instanceof ObjectInputStreamReadObjectMethod and
@@ -162,6 +298,14 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
162298 ma .getMethod ( ) instanceof CastorUnmarshalMethod and sink = ma .getAnArgument ( )
163299 or
164300 ma .getMethod ( ) instanceof BurlapInputReadObjectMethod and sink = ma .getQualifier ( )
301+ or
302+ ma .getMethod ( ) instanceof ObjectMapperReadMethod and
303+ sink = ma .getArgument ( 0 ) and
304+ (
305+ exists ( EnabledJacksonDefaultTyping config | config .hasFlowToExpr ( ma .getQualifier ( ) ) ) or
306+ hasJsonTypeInfoAnnotation ( ma .getArgument ( 1 ) .getType ( ) .( ParameterizedType ) .getATypeArgument ( ) )
307+ ) and
308+ not exists ( SafeObjectMapper config | config .hasFlowToExpr ( ma .getQualifier ( ) ) )
165309 )
166310}
167311
0 commit comments