Coverage for graphqler / fuzzer / engine / detectors / path_injection / path_injection_detector.py: 58%

40 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-18 23:20 -0400

1from typing import Type, override 

2 

3import requests 

4 

5from graphqler.utils.api import API 

6 

7from ...materializers.getter import Getter 

8from ...materializers.injection_materializer import InjectionMaterializer 

9from ..detector import Detector 

10 

11 

12# The main class that's being used 

13class PathInjectionMaterializer(InjectionMaterializer): 

14 def __init__(self, api: API, fail_on_hard_dependency_not_met: bool = False, max_depth: int = 20): 

15 super().__init__(api, fail_on_hard_dependency_not_met) 

16 self.api = api 

17 self.fail_on_hard_dependency_not_met = fail_on_hard_dependency_not_met 

18 self.max_depth = max_depth 

19 self.getter = PathInjectionGetter() 

20 

21 

22# Override the getters class to add custom getters for SQL injection 

23class PathInjectionGetter(Getter): 

24 def __init__(self): 

25 super().__init__() 

26 

27 @override 

28 def get_random_string(self, input_name: str) -> str: 

29 return '"../../../../etc/passwd"' 

30 

31 

32class PathInjectionDetector(Detector): 

33 @property 

34 def DETECTION_NAME(self) -> str: 

35 return "Path Injection" 

36 

37 @property 

38 def detect_only_once_for_api(self) -> bool: 

39 return False 

40 

41 @property 

42 def detect_only_once_for_node(self) -> bool: 

43 return True 

44 

45 @property 

46 def materializer(self) -> Type[PathInjectionMaterializer]: 

47 return PathInjectionMaterializer 

48 

49 def _is_vulnerable(self, graphql_response: dict, request_response: requests.Response) -> bool: 

50 if graphql_response is None or 'data' not in graphql_response or graphql_response['data'] is None: 

51 return False 

52 return "root:x:0:0:root:" in request_response.text or "root:x:0:0:root:" in str(graphql_response['data']) 

53 

54 def _is_potentially_vulnerable(self, graphql_response: dict, request_response: requests.Response) -> bool: 

55 if graphql_response is None or 'data' not in graphql_response or graphql_response['data'] is None: 

56 return False 

57 return ((graphql_response['data'] is not None and "Permission denied" in request_response.text) 

58 or ('../../../../etc/passwd' in request_response.text))