Skip to content

Commit bb2bd3b

Browse files
committed
Added prompt file and added logging of prompt
1 parent 290b148 commit bb2bd3b

File tree

8 files changed

+92
-46
lines changed

8 files changed

+92
-46
lines changed

‎src/hackingBuddyGPT/usecases/web_api_testing/documentation/openapi_specification_handler.py‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ def __init__(self, llm_handler: LLMHandler, response_handler: ResponseHandler, s
4242
self.query_params = {}
4343
self.endpoint_methods = {}
4444
self.endpoint_examples = {}
45-
self.filename = f"{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.yaml"
45+
date = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
46+
self.filename = f"{name}_spec.yaml"
4647
self.openapi_spec = {
4748
"openapi": "3.0.0",
4849
"info": {
@@ -57,7 +58,7 @@ def __init__(self, llm_handler: LLMHandler, response_handler: ResponseHandler, s
5758
self.llm_handler = llm_handler
5859
current_path = os.path.dirname(os.path.abspath(__file__))
5960

60-
self.file_path = os.path.join(current_path, "openapi_spec", str(strategy).split(".")[1].lower(), name.lower())
61+
self.file_path = os.path.join(current_path, "openapi_spec", str(strategy).split(".")[1].lower(), name.lower(), date)
6162
os.makedirs(self.file_path, exist_ok=True)
6263
self.file = os.path.join(self.file_path, self.filename)
6364

‎src/hackingBuddyGPT/usecases/web_api_testing/response_processing/response_handler.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -960,7 +960,6 @@ def check_if_successful(self, is_successful, request_path, result_dict, result_s
960960
if error_msg not in self.prompt_helper.correct_endpoint_but_some_error:
961961
self.prompt_helper.correct_endpoint_but_some_error[error_msg] = []
962962
self.prompt_helper.correct_endpoint_but_some_error[error_msg].append(request_path)
963-
self.prompt_helper.hint_for_next_round = error_msg
964963
else:
965964
self.prompt_helper.unsuccessful_paths.append(request_path)
966965
status_message = f"{request_path} is not a correct endpoint; Reason: {error_msg}"

‎src/hackingBuddyGPT/usecases/web_api_testing/simple_openapi_documentation.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def _initialize_handlers(self, config, description, token, name, initial_prompt)
162162

163163
self._prompt_engineer = PromptEngineer(
164164
strategy=self.strategy,
165-
context=None,
165+
context=PromptContext.DOCUMENTATION,
166166
prompt_helper=self.prompt_helper,
167167
open_api_spec=self._documentation_handler.openapi_spec,
168168
rest_api_info=(token, self.host, self._correct_endpoints, self.categorized_endpoints),

‎src/hackingBuddyGPT/utils/prompt_generation/prompts/basic_prompt.py‎

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -84,27 +84,15 @@ def generate_prompt(
8484
pass
8585

8686
def get_documentation_steps(self):
87-
"""
88-
Returns a predefined list of endpoint exploration steps based on the target API host.
89-
90-
These steps are used to guide automated documentation of a web API by progressively
91-
discovering and querying endpoints using GET requests. The process follows a structured
92-
hierarchy from root-level endpoints to more complex nested endpoints and those with query parameters.
93-
94-
Returns:
95-
List[List[str]]: A list of steps, each step being a list of instruction strings.
96-
"""
97-
98-
# Define specific documentation steps based on the given strategy
99-
10087
return [
101-
[f"Objective: Identify all accessible endpoints via GET requests for {self.prompt_helper.host}. {self.prompt_helper._description}"],
88+
[
89+
f"Objective: Identify all accessible endpoints via GET requests for {self.prompt_helper.host}. {self.prompt_helper._description}"],
10290
[
10391
f""" Query root-level resource endpoints.
104-
Find root-level endpoints for {self.prompt_helper.host}.
105-
Only send GET requests to root-level endpoints with a single path component after the root. This means each path should have exactly one '/' followed by a single word (e.g., '/users', '/products').
106-
1. Send GET requests to new paths only, avoiding any in the lists above.
107-
2. Do not reuse previously tested paths."""
92+
Find root-level endpoints for {self.prompt_helper.host}.
93+
Only send GET requests to root-level endpoints with a single path component after the root. This means each path should have exactly one '/' followed by a single word (e.g., '/users', '/products').
94+
1. Send GET requests to new paths only, avoiding any in the lists above.
95+
2. Do not reuse previously tested paths."""
10896

10997
],
11098
[
@@ -119,7 +107,6 @@ def get_documentation_steps(self):
119107
"Identify subresource endpoints of the form `/resource/other_resource`.",
120108
"Query these endpoints to check if they return data related to the main resource without requiring an `id` parameter."
121109

122-
123110
],
124111

125112
[
@@ -138,6 +125,7 @@ def get_documentation_steps(self):
138125
"Construct and make GET requests to these endpoints using common query parameters (e.g. `/resource?param1=1&param2=3`) or based on documentation hints, testing until a valid request with query parameters is achieved."
139126
]
140127
]
128+
141129
def extract_properties(self):
142130
"""
143131
Extracts example values and data types from the 'Post' schema in the OpenAPI specification.

‎src/hackingBuddyGPT/utils/prompt_generation/prompts/state_learning/in_context_learning_prompt.py‎

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,21 +61,22 @@ def generate_prompt(
6161
str: The generated prompt.
6262
"""
6363
if self.context == PromptContext.DOCUMENTATION:
64-
steps = self._get_documentation_steps(move_type=move_type, previous_prompt=previous_prompt)
64+
steps = self._get_documentation_steps(move_type=move_type, previous_prompt=previous_prompt, doc_steps=self.get_documentation_steps())
6565
elif self.context == PromptContext.PENTESTING:
6666
steps = self._get_pentesting_steps(move_type=move_type)
6767
else:
68-
steps = self._get_documentation_steps(move_type=move_type, previous_prompt=previous_prompt)
68+
steps = self.parse_prompt_file()
69+
steps = self._get_documentation_steps(move_type=move_type, previous_prompt=previous_prompt,
70+
doc_steps=steps)
6971

70-
#steps = self.parse_prompt_file()
7172

7273

7374
if hint:
7475
steps = steps + [hint]
7576

7677
return self.prompt_helper._check_prompt(previous_prompt=previous_prompt, steps=steps)
7778

78-
def _get_documentation_steps(self, move_type: str, previous_prompt) -> List[str]:
79+
def _get_documentation_steps(self, move_type: str, previous_prompt, doc_steps: Any) -> List[str]:
7980
# Extract properties and example response
8081
if "endpoints" in self.open_api_spec:
8182
properties = self.extract_properties()
@@ -106,7 +107,6 @@ def _get_documentation_steps(self, move_type: str, previous_prompt) -> List[str]
106107
icl_prompt = ""
107108

108109
if move_type == "explore":
109-
doc_steps = self.get_documentation_steps()
110110
icl = [[f"Based on this information :\n{icl_prompt}\n" + doc_steps[0][0]]]
111111
# if self.current_step == 0:
112112
# self.current_step == 1
@@ -356,7 +356,3 @@ def get_props(self, data, result ):
356356
return result
357357

358358

359-
360-
361-
362-

‎src/hackingBuddyGPT/utils/prompt_generation/prompts/task_planning/chain_of_thought_prompt.py‎

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,21 +50,78 @@ def generate_prompt(
5050
"""
5151
if self.context == PromptContext.DOCUMENTATION:
5252
self.purpose = PromptPurpose.DOCUMENTATION
53-
chain_of_thought_steps = self._get_documentation_steps( [],move_type)
53+
chain_of_thought_steps = self._get_documentation_steps([],move_type, self.get_documentation_steps())
5454
chain_of_thought_steps = [chain_of_thought_steps[0]] + [
5555
"Let's think step by step"] + chain_of_thought_steps[1:]
5656

5757
elif self.context == PromptContext.PENTESTING:
5858
chain_of_thought_steps = self._get_pentesting_steps(move_type,"")
5959
else:
60-
chain_of_thought_steps = self.parse_prompt_file()
60+
steps = self.parse_prompt_file()
61+
chain_of_thought_steps = self._get_documentation_steps([],move_type, steps)
62+
6163
chain_of_thought_steps = [chain_of_thought_steps[0]] + [
6264
"Let's think step by step"] + chain_of_thought_steps[1:]
6365
if hint:
6466
chain_of_thought_steps.append(hint)
6567

6668
return self.prompt_helper._check_prompt(previous_prompt=previous_prompt, steps=chain_of_thought_steps)
6769

70+
def get_documentation_steps(self):
71+
"""
72+
Returns a predefined list of endpoint exploration steps based on the target API host.
73+
74+
These steps are used to guide automated documentation of a web API by progressively
75+
discovering and querying endpoints using GET requests. The process follows a structured
76+
hierarchy from root-level endpoints to more complex nested endpoints and those with query parameters.
77+
78+
Returns:
79+
List[List[str]]: A list of steps, each step being a list of instruction strings.
80+
"""
81+
82+
# Define specific documentation steps based on the given strategy
83+
84+
return [
85+
[f"Objective: Identify all accessible endpoints via GET requests for {self.prompt_helper.host}. {self.prompt_helper._description}"],
86+
[
87+
f""" Query root-level resource endpoints.
88+
Find root-level endpoints for {self.prompt_helper.host}.
89+
Only send GET requests to root-level endpoints with a single path component after the root. This means each path should have exactly one '/' followed by a single word (e.g., '/users', '/products').
90+
1. Send GET requests to new paths only, avoiding any in the lists above.
91+
2. Do not reuse previously tested paths."""
92+
93+
],
94+
[
95+
"Query Instance-level resource endpoint with id",
96+
"Look for Instance-level resource endpoint : Identify endpoints of type `/resource/id` where id is the parameter for the id.",
97+
"Query these `/resource/id` endpoints to see if an `id` parameter resolves the request successfully."
98+
"Ids can be integers, longs or base62."
99+
100+
],
101+
[
102+
"Query Subresource Endpoints",
103+
"Identify subresource endpoints of the form `/resource/other_resource`.",
104+
"Query these endpoints to check if they return data related to the main resource without requiring an `id` parameter."
105+
106+
107+
],
108+
109+
[
110+
"Query for related resource endpoints",
111+
"Identify related resource endpoints that match the format `/resource/id/other_resource`: "
112+
f"First, scan for the follwoing endpoints where an `id` in the middle position and follow them by another resource identifier.",
113+
"Second, look for other endpoints and query these endpoints with appropriate `id` values to determine their behavior and document responses or errors."
114+
],
115+
[
116+
"Query multi-level resource endpoints",
117+
"Search for multi-level endpoints of type `/resource/other_resource/another_resource`: Identify any endpoints in the format with three resource identifiers.",
118+
"Test requests to these endpoints, adjusting resource identifiers as needed, and analyze responses to understand any additional parameters or behaviors."
119+
],
120+
[
121+
"Query endpoints with query parameters",
122+
"Construct and make GET requests to these endpoints using common query parameters (e.g. `/resource?param1=1&param2=3`) or based on documentation hints, testing until a valid request with query parameters is achieved."
123+
]
124+
]
68125

69126

70127
def transform_into_prompt_structure(self, test_case, purpose):

‎src/hackingBuddyGPT/utils/prompt_generation/prompts/task_planning/task_planning_prompt.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def __init__(self, context: PromptContext, prompt_helper, strategy: PromptStrate
4949
self.transformed_steps = {}
5050
self.pentest_steps = None
5151

52-
def _get_documentation_steps(self, common_steps: List[str], move_type: str) -> List[str]:
52+
def _get_documentation_steps(self, common_steps: List[str], move_type: str, steps: Any) -> List[str]:
5353
"""
5454
Provides the steps for the chain-of-thought strategy when the context is documentation.
5555
@@ -61,7 +61,7 @@ def _get_documentation_steps(self, common_steps: List[str], move_type: str) -> L
6161
List[str]: A list of steps for the chain-of-thought strategy in the documentation context.
6262
"""
6363
if move_type == "explore":
64-
doc_steps = self.generate_documentation_steps()
64+
doc_steps = self.generate_documentation_steps(steps)
6565
return self.prompt_helper.get_initial_documentation_steps(
6666
strategy_steps= doc_steps)
6767
else:

‎src/hackingBuddyGPT/utils/prompt_generation/prompts/task_planning/tree_of_thought_prompt.py‎

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,17 @@ def generate_prompt(self, move_type: str, hint: Optional[str], previous_prompt:
5454
common_steps = self._get_common_steps()
5555
if self.context == PromptContext.DOCUMENTATION:
5656
self.purpose = PromptPurpose.DOCUMENTATION
57-
tree_of_thought_steps = self._get_documentation_steps(common_steps, move_type)
57+
tree_of_thought_steps = self._get_documentation_steps(common_steps, move_type, self.get_documentation_steps())
5858
tree_of_thought_steps = [
5959
"Imagine three experts each proposing one step at a time. If an expert realizes their step was incorrect, they leave. The question is:"] + tree_of_thought_steps
6060

6161
elif self.context == PromptContext.PENTESTING:
6262
tree_of_thought_steps = self._get_pentesting_steps(move_type)
6363
else:
64-
tree_of_thought_steps = self.parse_prompt_file()
64+
steps = self.parse_prompt_file()
65+
66+
tree_of_thought_steps = self._get_documentation_steps(common_steps, move_type, steps)
67+
6568

6669
tree_of_thought_steps = ([
6770
"Imagine three experts each proposing one step at a time. If an expert realizes their step was incorrect, they leave. The question is:"] +
@@ -266,10 +269,10 @@ def transform_to_tree_of_thoughtx(self, prompts: Dict[str, List[List[str]]]) ->
266269

267270
return tot_prompts
268271

269-
270-
def generate_documentation_steps(self):
271-
return [
272-
[f"Objective: Identify all accessible endpoints via GET requests for {self.prompt_helper.host}. {self.prompt_helper._description}"],
272+
def get_documentation_steps(self):
273+
return [
274+
[
275+
f"Objective: Identify all accessible endpoints via GET requests for {self.prompt_helper.host}. {self.prompt_helper._description}"],
273276
[
274277
"Start by querying root-level resource endpoints.",
275278
"Focus on sending GET requests only to those endpoints that consist of a single path component directly following the root.",
@@ -282,10 +285,10 @@ def generate_documentation_steps(self):
282285
"Attempt to query these endpoints to validate whether the 'id' parameter correctly retrieves individual resource instances.",
283286
"Consider testing with various ID formats, such as integers, longs, or base62 encodings like '6rqhFgbbKwnb9MLmUQDhG6'."
284287
],
285-
["Now, move to query Subresource Endpoints.",
286-
"Identify subresource endpoints of the form `/resource/other_resource`.",
287-
"Query these endpoints to check if they return data related to the main resource without requiring an `id` parameter."
288-
],
288+
["Now, move to query Subresource Endpoints.",
289+
"Identify subresource endpoints of the form `/resource/other_resource`.",
290+
"Query these endpoints to check if they return data related to the main resource without requiring an `id` parameter."
291+
],
289292
[
290293
"Proceed to analyze related resource endpoints.",
291294
"Identify patterns where a resource is associated with another through an 'id', formatted as `/resource/id/other_resource`.",
@@ -305,3 +308,5 @@ def generate_documentation_steps(self):
305308
]
306309
]
307310

311+
def generate_documentation_steps(self, steps):
312+
return self.generate_documentation_steps(steps)

0 commit comments

Comments
 (0)