Add new configuration and tools
Browse files- .env.template +11 -0
- __pycache__/Gradio_UI.cpython-310.pyc +0 -0
- agent.json +37 -3
- app.py +97 -95
- prompts.yaml +1 -7
- tools/__pycache__/final_answer.cpython-310.pyc +0 -0
- tools/__pycache__/visit_webpage.cpython-310.pyc +0 -0
- tools/__pycache__/vuln_search.cpython-310.pyc +0 -0
- tools/__pycache__/web_search.cpython-310.pyc +0 -0
- tools/final_answer.py +1 -1
- tools/visit_webpage.py +2 -1
- tools/vuln_search.py +62 -0
- tools/web_search.py +1 -1
.env.template
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# API Keys and Endpoints
|
2 |
+
NVD_API_KEY=""
|
3 |
+
|
4 |
+
# Model Configuration
|
5 |
+
MODEL_ID="Qwen/Qwen2.5-Coder-32B-Instruct"
|
6 |
+
MAX_TOKENS=2096
|
7 |
+
TEMPERATURE=0.3
|
8 |
+
|
9 |
+
# Application Configuration
|
10 |
+
ENV="development"
|
11 |
+
DEBUG=true
|
__pycache__/Gradio_UI.cpython-310.pyc
ADDED
Binary file (6.81 kB). View file
|
|
agent.json
CHANGED
@@ -1,9 +1,43 @@
|
|
1 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
"tools": [
|
3 |
-
|
4 |
-
|
5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
],
|
|
|
|
|
|
|
|
|
|
|
7 |
"model": {
|
8 |
"class": "HfApiModel",
|
9 |
"data": {
|
|
|
1 |
{
|
2 |
+
"agent_config": {
|
3 |
+
"name": "VulnerabilityIntelligenceAgent",
|
4 |
+
"description": "Agente especializado en análisis de vulnerabilidades y amenazas de ciberseguridad",
|
5 |
+
"model": {
|
6 |
+
"type": "HfApiModel",
|
7 |
+
"model_id": "Qwen/Qwen2.5-Coder-32B-Instruct",
|
8 |
+
"max_tokens": 2096,
|
9 |
+
"temperature": 0.3
|
10 |
+
},
|
11 |
+
"max_steps": 10,
|
12 |
+
"verbosity_level": 2
|
13 |
+
},
|
14 |
"tools": [
|
15 |
+
{
|
16 |
+
"name": "final_answer",
|
17 |
+
"type": "FinalAnswerTool",
|
18 |
+
"description": "Proporciona una respuesta final al problema"
|
19 |
+
},
|
20 |
+
{
|
21 |
+
"name": "web_search",
|
22 |
+
"type": "DuckDuckGoSearchTool",
|
23 |
+
"description": "Realiza búsquedas web usando DuckDuckGo"
|
24 |
+
},
|
25 |
+
{
|
26 |
+
"name": "visit_webpage",
|
27 |
+
"type": "VisitWebpageTool",
|
28 |
+
"description": "Visita y extrae contenido de páginas web"
|
29 |
+
},
|
30 |
+
{
|
31 |
+
"name": "vuln_search",
|
32 |
+
"type": "VulnerabilitySearchTool",
|
33 |
+
"description": "Busca información sobre vulnerabilidades en múltiples fuentes"
|
34 |
+
}
|
35 |
],
|
36 |
+
"prompt_templates": {
|
37 |
+
"path": "prompts.yaml",
|
38 |
+
"default_system_prompt": "system_prompt",
|
39 |
+
"default_user_prompt": "user_prompt"
|
40 |
+
},
|
41 |
"model": {
|
42 |
"class": "HfApiModel",
|
43 |
"data": {
|
app.py
CHANGED
@@ -1,113 +1,115 @@
|
|
1 |
-
#!/usr/bin/env python3
|
2 |
-
"""
|
3 |
-
Gradio UI for the Vulnerability Intelligence Agent (VIA).
|
4 |
-
This provides a chat interface to interact with the VIA using natural language.
|
5 |
-
"""
|
6 |
import os
|
7 |
-
import
|
8 |
-
import
|
9 |
-
import
|
10 |
-
from typing import Dict, List, Any, Optional
|
11 |
-
|
12 |
import gradio as gr
|
13 |
-
from smolagents import CodeAgent
|
14 |
-
from smolagents.
|
15 |
-
|
16 |
-
|
17 |
-
|
|
|
18 |
|
19 |
-
|
20 |
-
|
21 |
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
)
|
27 |
-
logger = utils.setup_logger("gradio_ui")
|
28 |
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
"""
|
34 |
-
Get the description for the agent.
|
35 |
-
"""
|
36 |
-
return """
|
37 |
-
# 🔐 Vulnerability Intelligence Agent (VIA)
|
38 |
-
|
39 |
-
I am an intelligent agent designed to help you find vulnerabilities in software and systems.
|
40 |
-
|
41 |
-
## What I can do:
|
42 |
-
- Search for known vulnerabilities in software by name and version
|
43 |
-
- Provide detailed information about specific vulnerabilities (CVE, CWE, etc.)
|
44 |
-
- Generate reports about vulnerabilities
|
45 |
-
|
46 |
-
## How to use me:
|
47 |
-
- Ask about vulnerabilities in specific software, e.g., "Find vulnerabilities in OpenSSL 1.1.1k"
|
48 |
-
- Ask about a specific vulnerability, e.g., "Tell me about CVE-2021-44228"
|
49 |
-
- Use natural language to describe what you're looking for
|
50 |
-
|
51 |
-
## Examples:
|
52 |
-
- "What vulnerabilities exist in Apache 2.4.54?"
|
53 |
-
- "Are there any critical vulnerabilities in log4j 2.14.1?"
|
54 |
-
- "Give me details about CVE-2021-44228"
|
55 |
-
- "What security issues should I be aware of in OpenSSL 1.1.1k?"
|
56 |
-
"""
|
57 |
|
58 |
-
def
|
59 |
-
"""
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
return parser
|
69 |
|
70 |
-
def
|
71 |
-
"""
|
72 |
-
|
|
|
73 |
|
74 |
-
# Configure
|
75 |
-
|
76 |
-
logging.basicConfig(level=log_level)
|
77 |
-
|
78 |
-
# Initialize the model
|
79 |
model = HfApiModel(
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
custom_role_conversions=None,
|
84 |
)
|
85 |
|
86 |
-
# Initialize
|
|
|
|
|
|
|
87 |
agent = CodeAgent(
|
88 |
model=model,
|
89 |
-
tools=
|
90 |
-
max_steps=
|
91 |
-
verbosity_level=
|
92 |
)
|
93 |
|
94 |
-
|
95 |
-
|
|
|
|
|
|
|
96 |
|
97 |
-
#
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
|
112 |
if __name__ == "__main__":
|
113 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import os
|
2 |
+
import json
|
3 |
+
import yaml
|
4 |
+
from dotenv import load_dotenv
|
|
|
|
|
5 |
import gradio as gr
|
6 |
+
from smolagents import CodeAgent
|
7 |
+
from smolagents.models import HfApiModel
|
8 |
+
from tools.final_answer import FinalAnswerTool
|
9 |
+
from tools.web_search import DuckDuckGoSearchTool
|
10 |
+
from tools.visit_webpage import VisitWebpageTool
|
11 |
+
from tools.vuln_search import VulnerabilitySearchTool
|
12 |
|
13 |
+
# Load environment variables
|
14 |
+
load_dotenv()
|
15 |
|
16 |
+
def load_agent_config():
|
17 |
+
"""Load agent configuration from agent.json"""
|
18 |
+
with open('agent.json', 'r') as f:
|
19 |
+
return json.load(f)
|
|
|
|
|
20 |
|
21 |
+
def load_prompts():
|
22 |
+
"""Load prompt templates from prompts.yaml"""
|
23 |
+
with open('prompts.yaml', 'r') as f:
|
24 |
+
return yaml.safe_load(f)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
|
26 |
+
def initialize_tools():
|
27 |
+
"""Initialize agent tools"""
|
28 |
+
tools = {
|
29 |
+
'final_answer': FinalAnswerTool(),
|
30 |
+
'web_search': DuckDuckGoSearchTool(),
|
31 |
+
'visit_webpage': VisitWebpageTool(),
|
32 |
+
'vuln_search': VulnerabilitySearchTool()
|
33 |
+
}
|
34 |
+
return tools
|
|
|
|
|
35 |
|
36 |
+
def create_agent():
|
37 |
+
"""Create and configure the vulnerability agent"""
|
38 |
+
config = load_agent_config()
|
39 |
+
prompts = load_prompts()
|
40 |
|
41 |
+
# Configure model
|
42 |
+
model_config = config['agent_config']['model']
|
|
|
|
|
|
|
43 |
model = HfApiModel(
|
44 |
+
model_id=model_config['model_id'],
|
45 |
+
max_tokens=model_config['max_tokens'],
|
46 |
+
temperature=model_config['temperature']
|
|
|
47 |
)
|
48 |
|
49 |
+
# Initialize tools
|
50 |
+
tools = initialize_tools()
|
51 |
+
|
52 |
+
# Create agent
|
53 |
agent = CodeAgent(
|
54 |
model=model,
|
55 |
+
tools=tools,
|
56 |
+
max_steps=config['agent_config']['max_steps'],
|
57 |
+
verbosity_level=config['agent_config']['verbosity_level']
|
58 |
)
|
59 |
|
60 |
+
return agent, prompts
|
61 |
+
|
62 |
+
def process_query(query, analysis_type="general"):
|
63 |
+
"""Process a user query"""
|
64 |
+
agent, prompts = create_agent()
|
65 |
|
66 |
+
# Select appropriate template
|
67 |
+
if analysis_type == "vulnerability":
|
68 |
+
template = prompts['vulnerability_analysis']
|
69 |
+
formatted_prompt = template.format(cve_id=query)
|
70 |
+
elif analysis_type == "threat":
|
71 |
+
template = prompts['threat_report']
|
72 |
+
formatted_prompt = template.format(target=query)
|
73 |
+
else:
|
74 |
+
template = prompts['user_prompt']
|
75 |
+
formatted_prompt = template.format(query=query)
|
76 |
+
|
77 |
+
# Execute agent
|
78 |
+
system_prompt = prompts['system_prompt']
|
79 |
+
result = agent.run(formatted_prompt, system_prompt=system_prompt)
|
80 |
+
|
81 |
+
return result
|
82 |
+
|
83 |
+
# Gradio Interface
|
84 |
+
def create_interface():
|
85 |
+
"""Create the Gradio user interface"""
|
86 |
+
with gr.Blocks(title="Vulnerability Intelligence Agent") as interface:
|
87 |
+
gr.Markdown("# Vulnerability Intelligence Agent (VIA)")
|
88 |
+
|
89 |
+
with gr.Row():
|
90 |
+
with gr.Column():
|
91 |
+
query_input = gr.Textbox(
|
92 |
+
label="Query",
|
93 |
+
placeholder="Enter your security query..."
|
94 |
+
)
|
95 |
+
analysis_type = gr.Radio(
|
96 |
+
choices=["general", "vulnerability", "threat"],
|
97 |
+
label="Analysis Type",
|
98 |
+
value="general"
|
99 |
+
)
|
100 |
+
submit_btn = gr.Button("Analyze")
|
101 |
+
|
102 |
+
with gr.Column():
|
103 |
+
output = gr.Markdown(label="Result")
|
104 |
+
|
105 |
+
submit_btn.click(
|
106 |
+
fn=process_query,
|
107 |
+
inputs=[query_input, analysis_type],
|
108 |
+
outputs=output
|
109 |
+
)
|
110 |
+
|
111 |
+
return interface
|
112 |
|
113 |
if __name__ == "__main__":
|
114 |
+
interface = create_interface()
|
115 |
+
interface.launch()
|
prompts.yaml
CHANGED
@@ -186,7 +186,6 @@
|
|
186 |
"planning":
|
187 |
"initial_facts": |-
|
188 |
Below I will present you a task.
|
189 |
-
|
190 |
You will now build a comprehensive preparatory survey of which facts we have at our disposal and which ones we still need.
|
191 |
To do so, you will have to read the task and identify things that must be discovered in order to successfully complete it.
|
192 |
Don't make any assumptions. For each item, provide a thorough reasoning. Here is how you will structure this survey:
|
@@ -209,7 +208,6 @@
|
|
209 |
Do not add anything else.
|
210 |
"initial_plan": |-
|
211 |
You are a world expert at making efficient plans to solve any task using a set of carefully crafted tools.
|
212 |
-
|
213 |
Now for the given task, develop a step-by-step high-level plan taking into account the above inputs and list of facts.
|
214 |
This plan should involve individual tasks based on the available tools, that if executed correctly will yield the correct answer.
|
215 |
Do not skip steps, do not add any superfluous steps. Only write the high-level plan, DO NOT DETAIL INDIVIDUAL TOOL CALLS.
|
@@ -261,11 +259,9 @@
|
|
261 |
### 2. Facts that we have learned
|
262 |
### 3. Facts still to look up
|
263 |
### 4. Facts still to derive
|
264 |
-
|
265 |
Now write your new list of facts below.
|
266 |
"update_plan_pre_messages": |-
|
267 |
You are a world expert at making efficient plans to solve any task using a set of carefully crafted tools.
|
268 |
-
|
269 |
You have been given a task:
|
270 |
```
|
271 |
{{task}}
|
@@ -279,7 +275,6 @@
|
|
279 |
```
|
280 |
{{task}}
|
281 |
```
|
282 |
-
|
283 |
You can leverage these tools:
|
284 |
{%- for tool in tools.values() %}
|
285 |
- {{ tool.name }}: {{ tool.description }}
|
@@ -319,7 +314,6 @@
|
|
319 |
{{task}}
|
320 |
---
|
321 |
You're helping your manager solve a wider task: so make sure to not provide a one-line answer, but give as much information as possible to give them a clear understanding of the answer.
|
322 |
-
|
323 |
Your final_answer WILL HAVE to contain these parts:
|
324 |
### 1. Task outcome (short version):
|
325 |
### 2. Task outcome (extremely detailed version):
|
@@ -329,4 +323,4 @@
|
|
329 |
And even if your task resolution is not successful, please return as much context as possible, so that your manager can act upon this feedback.
|
330 |
"report": |-
|
331 |
Here is the final answer from your managed agent '{{name}}':
|
332 |
-
{{final_answer}}
|
|
|
186 |
"planning":
|
187 |
"initial_facts": |-
|
188 |
Below I will present you a task.
|
|
|
189 |
You will now build a comprehensive preparatory survey of which facts we have at our disposal and which ones we still need.
|
190 |
To do so, you will have to read the task and identify things that must be discovered in order to successfully complete it.
|
191 |
Don't make any assumptions. For each item, provide a thorough reasoning. Here is how you will structure this survey:
|
|
|
208 |
Do not add anything else.
|
209 |
"initial_plan": |-
|
210 |
You are a world expert at making efficient plans to solve any task using a set of carefully crafted tools.
|
|
|
211 |
Now for the given task, develop a step-by-step high-level plan taking into account the above inputs and list of facts.
|
212 |
This plan should involve individual tasks based on the available tools, that if executed correctly will yield the correct answer.
|
213 |
Do not skip steps, do not add any superfluous steps. Only write the high-level plan, DO NOT DETAIL INDIVIDUAL TOOL CALLS.
|
|
|
259 |
### 2. Facts that we have learned
|
260 |
### 3. Facts still to look up
|
261 |
### 4. Facts still to derive
|
|
|
262 |
Now write your new list of facts below.
|
263 |
"update_plan_pre_messages": |-
|
264 |
You are a world expert at making efficient plans to solve any task using a set of carefully crafted tools.
|
|
|
265 |
You have been given a task:
|
266 |
```
|
267 |
{{task}}
|
|
|
275 |
```
|
276 |
{{task}}
|
277 |
```
|
|
|
278 |
You can leverage these tools:
|
279 |
{%- for tool in tools.values() %}
|
280 |
- {{ tool.name }}: {{ tool.description }}
|
|
|
314 |
{{task}}
|
315 |
---
|
316 |
You're helping your manager solve a wider task: so make sure to not provide a one-line answer, but give as much information as possible to give them a clear understanding of the answer.
|
|
|
317 |
Your final_answer WILL HAVE to contain these parts:
|
318 |
### 1. Task outcome (short version):
|
319 |
### 2. Task outcome (extremely detailed version):
|
|
|
323 |
And even if your task resolution is not successful, please return as much context as possible, so that your manager can act upon this feedback.
|
324 |
"report": |-
|
325 |
Here is the final answer from your managed agent '{{name}}':
|
326 |
+
{{final_answer}}
|
tools/__pycache__/final_answer.cpython-310.pyc
ADDED
Binary file (898 Bytes). View file
|
|
tools/__pycache__/visit_webpage.cpython-310.pyc
ADDED
Binary file (1.9 kB). View file
|
|
tools/__pycache__/vuln_search.cpython-310.pyc
ADDED
Binary file (3.9 kB). View file
|
|
tools/__pycache__/web_search.cpython-310.pyc
ADDED
Binary file (1.77 kB). View file
|
|
tools/final_answer.py
CHANGED
@@ -11,4 +11,4 @@ class FinalAnswerTool(Tool):
|
|
11 |
return answer
|
12 |
|
13 |
def __init__(self, *args, **kwargs):
|
14 |
-
self.is_initialized = False
|
|
|
11 |
return answer
|
12 |
|
13 |
def __init__(self, *args, **kwargs):
|
14 |
+
self.is_initialized = False
|
tools/visit_webpage.py
CHANGED
@@ -3,6 +3,7 @@ from smolagents.tools import Tool
|
|
3 |
import requests
|
4 |
import markdownify
|
5 |
import smolagents
|
|
|
6 |
|
7 |
class VisitWebpageTool(Tool):
|
8 |
name = "visit_webpage"
|
@@ -42,4 +43,4 @@ class VisitWebpageTool(Tool):
|
|
42 |
return f"An unexpected error occurred: {str(e)}"
|
43 |
|
44 |
def __init__(self, *args, **kwargs):
|
45 |
-
self.is_initialized = False
|
|
|
3 |
import requests
|
4 |
import markdownify
|
5 |
import smolagents
|
6 |
+
import re
|
7 |
|
8 |
class VisitWebpageTool(Tool):
|
9 |
name = "visit_webpage"
|
|
|
43 |
return f"An unexpected error occurred: {str(e)}"
|
44 |
|
45 |
def __init__(self, *args, **kwargs):
|
46 |
+
self.is_initialized = False
|
tools/vuln_search.py
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from typing import Dict, Any, Optional, List
|
3 |
+
import nvdlib
|
4 |
+
from smolagents.tools import Tool
|
5 |
+
|
6 |
+
class VulnerabilitySearchTool(Tool):
|
7 |
+
name = "vuln_search"
|
8 |
+
description = "Search for vulnerabilities in NVD (National Vulnerability Database)"
|
9 |
+
inputs = {
|
10 |
+
'query': {'type': 'str', 'description': 'Search term or CVE ID'},
|
11 |
+
'max_results': {'type': 'int', 'description': 'Maximum number of results', 'default': 5}
|
12 |
+
}
|
13 |
+
output_type = Dict[str, Any]
|
14 |
+
|
15 |
+
def __init__(self):
|
16 |
+
"""Initialize NVD API connection"""
|
17 |
+
self.nvd_api_key = os.getenv('NVD_API_KEY')
|
18 |
+
|
19 |
+
# Configure NVD
|
20 |
+
if self.nvd_api_key:
|
21 |
+
nvdlib.set_api_key(self.nvd_api_key)
|
22 |
+
|
23 |
+
def search_nvd(self, query: str, max_results: int) -> List[Dict[str, Any]]:
|
24 |
+
"""Search vulnerabilities in NVD"""
|
25 |
+
try:
|
26 |
+
# If query looks like a CVE-ID, search directly
|
27 |
+
if query.startswith('CVE-'):
|
28 |
+
results = nvdlib.get_cve(query)
|
29 |
+
return [{
|
30 |
+
'id': results.id,
|
31 |
+
'description': results.descriptions[0].value,
|
32 |
+
'severity': results.metrics.cvssMetricV31[0].cvssData.baseScore if results.metrics else None,
|
33 |
+
'published': results.published,
|
34 |
+
'references': [ref.url for ref in results.references]
|
35 |
+
}]
|
36 |
+
|
37 |
+
# Otherwise, perform general search
|
38 |
+
results = nvdlib.searchCVE(
|
39 |
+
keyword=query,
|
40 |
+
limit=max_results
|
41 |
+
)
|
42 |
+
|
43 |
+
return [{
|
44 |
+
'id': r.id,
|
45 |
+
'description': r.descriptions[0].value,
|
46 |
+
'severity': r.metrics.cvssMetricV31[0].cvssData.baseScore if r.metrics else None,
|
47 |
+
'published': r.published,
|
48 |
+
'references': [ref.url for ref in r.references]
|
49 |
+
} for r in results]
|
50 |
+
|
51 |
+
except Exception as e:
|
52 |
+
return [{'error': f"Error in NVD search: {str(e)}"}]
|
53 |
+
|
54 |
+
def forward(self, query: str, max_results: int = 5) -> Dict[str, Any]:
|
55 |
+
"""Process search in NVD"""
|
56 |
+
results = self.search_nvd(query, max_results)
|
57 |
+
|
58 |
+
return {
|
59 |
+
'query': query,
|
60 |
+
'source': 'nvd',
|
61 |
+
'results': results
|
62 |
+
}
|
tools/web_search.py
CHANGED
@@ -24,4 +24,4 @@ class DuckDuckGoSearchTool(Tool):
|
|
24 |
if len(results) == 0:
|
25 |
raise Exception("No results found! Try a less restrictive/shorter query.")
|
26 |
postprocessed_results = [f"[{result['title']}]({result['href']})\n{result['body']}" for result in results]
|
27 |
-
return "## Search Results\n\n" + "\n\n".join(postprocessed_results)
|
|
|
24 |
if len(results) == 0:
|
25 |
raise Exception("No results found! Try a less restrictive/shorter query.")
|
26 |
postprocessed_results = [f"[{result['title']}]({result['href']})\n{result['body']}" for result in results]
|
27 |
+
return "## Search Results\n\n" + "\n\n".join(postprocessed_results)
|