11package dev .aikido .agent_api .helpers .extraction ;
22
33import dev .aikido .agent_api .helpers .patterns .LooksLikeJWT ;
4+ import dev .aikido .agent_api .vulnerabilities .DangerousBodyException ;
45import java .lang .reflect .Field ;
56import java .lang .reflect .Modifier ;
67import java .util .*;
910import static dev .aikido .agent_api .helpers .patterns .PrimitiveType .isPrimitiveType ;
1011
1112public class StringExtractor {
13+ private static final int MAX_DEPTH = 1024 ;
1214 // Ensures that we don't get recursion :
1315 Set <Object > scanned = new HashSet <>();
1416 public static Map <String , String > extractStringsFromObject (Object obj ) {
15- return new StringExtractor ().extractStringsRecursive (obj , new ArrayList <>());
17+ return new StringExtractor ().extractStringsRecursive (obj , new ArrayList <>(), 0 );
1618 }
17- private Map <String , String > extractStringsRecursive (Object target , ArrayList <PathBuilder .PathPart > pathToPayload ) {
19+ private Map <String , String > extractStringsRecursive (Object target , ArrayList <PathBuilder .PathPart > pathToPayload , int depth ) {
20+ if (depth > MAX_DEPTH ) {
21+ throw DangerousBodyException .bodyTooDeep ();
22+ }
1823 HashMap <String , String > result = new HashMap <>();
1924 if (target == null || scanned .contains (target )) {
2025 return Map .of (); // Do not rescan objects, because this might lead to recursion.
2126 }
2227 scanned .add (target );
2328
2429 if (target instanceof String targetString ) {
25- result .putAll (extractStringsFromString (targetString , pathToPayload ));
30+ result .putAll (extractStringsFromString (targetString , pathToPayload , depth ));
2631 } else if (target instanceof Collection <?> || target .getClass ().isArray ()) {
27- result .putAll (extractStringsFromArray (target , pathToPayload ));
32+ result .putAll (extractStringsFromArray (target , pathToPayload , depth ));
2833 } else if (target instanceof Map <?, ?> targetMap ) {
29- result .putAll (extractStringsFromMap (targetMap , pathToPayload ));
34+ result .putAll (extractStringsFromMap (targetMap , pathToPayload , depth ));
3035 } else if (!isPrimitiveType (target )) { // Stop algorithm if it's a primitive type.
31- result .putAll (extractStringsFromStructure (target , pathToPayload ));
36+ result .putAll (extractStringsFromStructure (target , pathToPayload , depth ));
3237 }
3338 return result ;
3439 }
3540
36- private Map <String , String > extractStringsFromString (String target , ArrayList <PathBuilder .PathPart > pathToPayload ) {
41+ private Map <String , String > extractStringsFromString (String target , ArrayList <PathBuilder .PathPart > pathToPayload , int depth ) {
3742 HashMap <String , String > result = new HashMap <>();
3843 result .put (target , buildPathToPayload (pathToPayload ));
3944
@@ -42,7 +47,7 @@ private Map<String, String> extractStringsFromString(String target, ArrayList<Pa
4247 if (jwtResult .success ()) {
4348 ArrayList <PathBuilder .PathPart > newPathToPayload = new ArrayList <>(pathToPayload );
4449 newPathToPayload .add (new PathBuilder .PathPart ("jwt" ));
45- Map <String , String > resultsFromJWT = extractStringsRecursive (jwtResult .payload (), newPathToPayload );
50+ Map <String , String > resultsFromJWT = extractStringsRecursive (jwtResult .payload (), newPathToPayload , depth + 1 );
4651 for (Map .Entry <String , String > entry : resultsFromJWT .entrySet ()) {
4752 String key = entry .getKey ();
4853 String value = entry .getValue ();
@@ -57,27 +62,27 @@ private Map<String, String> extractStringsFromString(String target, ArrayList<Pa
5762 return result ;
5863 }
5964
60- private Map <String , String > extractStringsFromArray (Object target , ArrayList <PathBuilder .PathPart > pathToPayload ) {
65+ private Map <String , String > extractStringsFromArray (Object target , ArrayList <PathBuilder .PathPart > pathToPayload , int depth ) {
6166 HashMap <String , String > result = new HashMap <>();
6267 if (target instanceof Collection <?> targetCollection ) {
6368 int index = 0 ;
6469 for (Object element : (Collection <?>) targetCollection ) {
6570 ArrayList <PathBuilder .PathPart > newPathToPayload = new ArrayList <>(pathToPayload );
6671 newPathToPayload .add (new PathBuilder .PathPart ("array" , index ));
67- result .putAll (extractStringsRecursive (element , newPathToPayload ));
72+ result .putAll (extractStringsRecursive (element , newPathToPayload , depth + 1 ));
6873 index ++;
6974 }
7075 } else if (target instanceof Object [] targetArray ) {
7176 for (int i = 0 ; i < targetArray .length ; i ++) {
7277 ArrayList <PathBuilder .PathPart > newPathToPayload = new ArrayList <>(pathToPayload );
7378 newPathToPayload .add (new PathBuilder .PathPart ("array" , i ));
74- result .putAll (extractStringsRecursive (targetArray [i ], newPathToPayload ));
79+ result .putAll (extractStringsRecursive (targetArray [i ], newPathToPayload , depth + 1 ));
7580 }
7681 }
7782 return result ;
7883 }
7984
80- private Map <String , String > extractStringsFromMap (Map <?, ?> target , ArrayList <PathBuilder .PathPart > pathToPayload ) {
85+ private Map <String , String > extractStringsFromMap (Map <?, ?> target , ArrayList <PathBuilder .PathPart > pathToPayload , int depth ) {
8186 HashMap <String , String > result = new HashMap <>();
8287 for (Object key : target .keySet ()) {
8388 if (key instanceof String stringKey ) {
@@ -89,12 +94,12 @@ private Map<String, String> extractStringsFromMap(Map<?, ?> target, ArrayList<Pa
8994 } else {
9095 newPathToPayload .add (new PathBuilder .PathPart ("object" , key .toString ()));
9196 }
92- result .putAll (extractStringsRecursive (target .get (key ), newPathToPayload ));
97+ result .putAll (extractStringsRecursive (target .get (key ), newPathToPayload , depth + 1 ));
9398 }
9499 return result ;
95100 }
96101
97- private Map <String , String > extractStringsFromStructure (Object target , ArrayList <PathBuilder .PathPart > pathToPayload ) {
102+ private Map <String , String > extractStringsFromStructure (Object target , ArrayList <PathBuilder .PathPart > pathToPayload , int depth ) {
98103 HashMap <String , String > result = new HashMap <>();
99104 Field [] fields = target .getClass ().getDeclaredFields ();
100105 for (Field field : fields ) {
@@ -106,7 +111,9 @@ private Map<String, String> extractStringsFromStructure(Object target, ArrayList
106111 Object fieldValue = field .get (target );
107112 ArrayList <PathBuilder .PathPart > newPathToPayload = new ArrayList <>(pathToPayload );
108113 newPathToPayload .add (new PathBuilder .PathPart ("object" , field .getName ()));
109- result .putAll (extractStringsRecursive (fieldValue , newPathToPayload ));
114+ result .putAll (extractStringsRecursive (fieldValue , newPathToPayload , depth + 1 ));
115+ } catch (DangerousBodyException e ) {
116+ throw e ;
110117 } catch (IllegalAccessException | RuntimeException e ) {
111118 // pass-through
112119 }
0 commit comments