Spaces:
Running
Running
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,384 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import torch
|
3 |
+
from transformers import AutoTokenizer, AutoModelForSequenceClassification
|
4 |
+
import numpy as np
|
5 |
+
import json
|
6 |
+
import re
|
7 |
+
import time
|
8 |
+
from datetime import datetime
|
9 |
+
import plotly.graph_objects as go
|
10 |
+
import plotly.express as px
|
11 |
+
from plotly.subplots import make_subplots
|
12 |
+
|
13 |
+
# Initialize SecBERT model
|
14 |
+
MODEL_NAME = "jackaduma/SecBERT"
|
15 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
|
16 |
+
model = AutoModelForSequenceClassification.from_pretrained(MODEL_NAME)
|
17 |
+
|
18 |
+
# Threat patterns and keywords
|
19 |
+
THREAT_PATTERNS = {
|
20 |
+
"malware": ["trojan", "virus", "worm", "ransomware", "backdoor", "rootkit", "botnet", "keylogger"],
|
21 |
+
"phishing": ["click here", "urgent action", "verify account", "suspended", "limited time", "act now"],
|
22 |
+
"social_engineering": ["confidential", "insider", "exclusive", "secret", "don't tell", "between us"],
|
23 |
+
"data_breach": ["leaked", "exposed", "unauthorized access", "data dump", "credentials", "database"],
|
24 |
+
"network_attack": ["ddos", "injection", "exploit", "payload", "shell", "reverse", "buffer overflow"],
|
25 |
+
"apt": ["advanced persistent", "nation state", "targeted", "spear phishing", "zero day", "lateral movement"]
|
26 |
+
}
|
27 |
+
|
28 |
+
DEMO_EXAMPLES = [
|
29 |
+
"Urgent: Your account has been suspended! Click this link immediately to verify your identity and restore access.",
|
30 |
+
"Our new trojan variant uses advanced persistence mechanisms and lateral movement techniques to maintain access.",
|
31 |
+
"The APT group deployed custom malware with zero-day exploits targeting financial institutions.",
|
32 |
+
"Database containing 2.3 million user credentials was found exposed on an unprotected server.",
|
33 |
+
"Hi there! Hope you're having a great day. Looking forward to our meeting tomorrow at 2 PM.",
|
34 |
+
"The SQL injection vulnerability allows attackers to dump the entire user database via union select queries."
|
35 |
+
]
|
36 |
+
|
37 |
+
def analyze_threat_patterns(text):
|
38 |
+
"""Analyze text for cybersecurity threat patterns"""
|
39 |
+
threat_scores = {}
|
40 |
+
detected_threats = []
|
41 |
+
|
42 |
+
text_lower = text.lower()
|
43 |
+
|
44 |
+
for threat_type, keywords in THREAT_PATTERNS.items():
|
45 |
+
score = 0
|
46 |
+
found_keywords = []
|
47 |
+
|
48 |
+
for keyword in keywords:
|
49 |
+
if keyword in text_lower:
|
50 |
+
score += 1
|
51 |
+
found_keywords.append(keyword)
|
52 |
+
|
53 |
+
if score > 0:
|
54 |
+
threat_scores[threat_type] = {
|
55 |
+
"score": min(score / len(keywords), 1.0),
|
56 |
+
"keywords": found_keywords
|
57 |
+
}
|
58 |
+
detected_threats.append(threat_type)
|
59 |
+
|
60 |
+
return threat_scores, detected_threats
|
61 |
+
|
62 |
+
def get_threat_level(threat_scores):
|
63 |
+
"""Calculate overall threat level"""
|
64 |
+
if not threat_scores:
|
65 |
+
return "safe", 0.0
|
66 |
+
|
67 |
+
max_score = max(threat_info["score"] for threat_info in threat_scores.values())
|
68 |
+
|
69 |
+
if max_score >= 0.4:
|
70 |
+
return "critical", max_score
|
71 |
+
elif max_score >= 0.25:
|
72 |
+
return "high", max_score
|
73 |
+
elif max_score >= 0.15:
|
74 |
+
return "medium", max_score
|
75 |
+
else:
|
76 |
+
return "low", max_score
|
77 |
+
|
78 |
+
def create_threat_visualization(threat_scores, overall_level, overall_score):
|
79 |
+
"""Create interactive threat visualization"""
|
80 |
+
if not threat_scores:
|
81 |
+
# Safe visualization
|
82 |
+
fig = go.Figure(go.Indicator(
|
83 |
+
mode = "gauge+number",
|
84 |
+
value = 0,
|
85 |
+
domain = {'x': [0, 1], 'y': [0, 1]},
|
86 |
+
title = {'text': "π’ SAFE"},
|
87 |
+
gauge = {
|
88 |
+
'axis': {'range': [None, 1]},
|
89 |
+
'bar': {'color': "green"},
|
90 |
+
'steps': [{'range': [0, 1], 'color': "lightgray"}],
|
91 |
+
'threshold': {'line': {'color': "red", 'width': 4},
|
92 |
+
'thickness': 0.75, 'value': 0.8}
|
93 |
+
}
|
94 |
+
))
|
95 |
+
else:
|
96 |
+
# Threat level colors
|
97 |
+
colors = {
|
98 |
+
"safe": "green",
|
99 |
+
"low": "yellow",
|
100 |
+
"medium": "orange",
|
101 |
+
"high": "red",
|
102 |
+
"critical": "darkred"
|
103 |
+
}
|
104 |
+
|
105 |
+
# Main gauge
|
106 |
+
fig = go.Figure(go.Indicator(
|
107 |
+
mode = "gauge+number+delta",
|
108 |
+
value = overall_score,
|
109 |
+
domain = {'x': [0, 1], 'y': [0, 1]},
|
110 |
+
title = {'text': f"π¨ {overall_level.upper()} THREAT"},
|
111 |
+
delta = {'reference': 0.5},
|
112 |
+
gauge = {
|
113 |
+
'axis': {'range': [None, 1]},
|
114 |
+
'bar': {'color': colors[overall_level]},
|
115 |
+
'steps': [
|
116 |
+
{'range': [0, 0.15], 'color': "lightgreen"},
|
117 |
+
{'range': [0.15, 0.25], 'color': "yellow"},
|
118 |
+
{'range': [0.25, 0.4], 'color': "orange"},
|
119 |
+
{'range': [0.4, 1], 'color': "red"}
|
120 |
+
],
|
121 |
+
'threshold': {'line': {'color': "black", 'width': 4},
|
122 |
+
'thickness': 0.75, 'value': 0.8}
|
123 |
+
}
|
124 |
+
))
|
125 |
+
|
126 |
+
fig.update_layout(
|
127 |
+
height=300,
|
128 |
+
font={'color': "white", 'family': "Arial"},
|
129 |
+
paper_bgcolor="rgba(0,0,0,0.1)",
|
130 |
+
plot_bgcolor="rgba(0,0,0,0)"
|
131 |
+
)
|
132 |
+
|
133 |
+
return fig
|
134 |
+
|
135 |
+
def create_threat_breakdown(threat_scores):
|
136 |
+
"""Create threat category breakdown chart"""
|
137 |
+
if not threat_scores:
|
138 |
+
return None
|
139 |
+
|
140 |
+
categories = list(threat_scores.keys())
|
141 |
+
scores = [threat_scores[cat]["score"] for cat in categories]
|
142 |
+
|
143 |
+
colors = px.colors.qualitative.Set3
|
144 |
+
|
145 |
+
fig = go.Figure(data=[
|
146 |
+
go.Bar(
|
147 |
+
x=categories,
|
148 |
+
y=scores,
|
149 |
+
marker_color=colors[:len(categories)],
|
150 |
+
text=[f"{s:.1%}" for s in scores],
|
151 |
+
textposition='auto',
|
152 |
+
)
|
153 |
+
])
|
154 |
+
|
155 |
+
fig.update_layout(
|
156 |
+
title="Threat Categories Detected",
|
157 |
+
xaxis_title="Threat Type",
|
158 |
+
yaxis_title="Threat Score",
|
159 |
+
height=400,
|
160 |
+
font={'color': "white"},
|
161 |
+
paper_bgcolor="rgba(0,0,0,0.1)",
|
162 |
+
plot_bgcolor="rgba(0,0,0,0)"
|
163 |
+
)
|
164 |
+
|
165 |
+
return fig
|
166 |
+
|
167 |
+
def highlight_threats_in_text(text, threat_scores):
|
168 |
+
"""Highlight detected threats in the original text"""
|
169 |
+
if not threat_scores:
|
170 |
+
return text
|
171 |
+
|
172 |
+
highlighted_text = text
|
173 |
+
colors = ["#ff6b6b", "#4ecdc4", "#45b7d1", "#96ceb4", "#ffeaa7", "#dda0dd"]
|
174 |
+
|
175 |
+
color_idx = 0
|
176 |
+
for threat_type, threat_info in threat_scores.items():
|
177 |
+
color = colors[color_idx % len(colors)]
|
178 |
+
for keyword in threat_info["keywords"]:
|
179 |
+
pattern = re.compile(re.escape(keyword), re.IGNORECASE)
|
180 |
+
highlighted_text = pattern.sub(
|
181 |
+
f'<mark style="background-color: {color}; padding: 2px 4px; border-radius: 3px; font-weight: bold;">{keyword}</mark>',
|
182 |
+
highlighted_text
|
183 |
+
)
|
184 |
+
color_idx += 1
|
185 |
+
|
186 |
+
return highlighted_text
|
187 |
+
|
188 |
+
def analyze_cybersecurity_threat(text, progress=gr.Progress()):
|
189 |
+
"""Main threat analysis function"""
|
190 |
+
progress(0, desc="Initializing analysis...")
|
191 |
+
time.sleep(0.5)
|
192 |
+
|
193 |
+
progress(0.2, desc="Scanning for threat patterns...")
|
194 |
+
threat_scores, detected_threats = analyze_threat_patterns(text)
|
195 |
+
time.sleep(0.3)
|
196 |
+
|
197 |
+
progress(0.5, desc="Calculating threat levels...")
|
198 |
+
overall_level, overall_score = get_threat_level(threat_scores)
|
199 |
+
time.sleep(0.3)
|
200 |
+
|
201 |
+
progress(0.7, desc="Generating visualizations...")
|
202 |
+
gauge_chart = create_threat_visualization(threat_scores, overall_level, overall_score)
|
203 |
+
breakdown_chart = create_threat_breakdown(threat_scores)
|
204 |
+
time.sleep(0.3)
|
205 |
+
|
206 |
+
progress(0.9, desc="Highlighting threats in text...")
|
207 |
+
highlighted_text = highlight_threats_in_text(text, threat_scores)
|
208 |
+
|
209 |
+
# Generate detailed analysis
|
210 |
+
analysis_report = generate_analysis_report(threat_scores, overall_level, overall_score, detected_threats)
|
211 |
+
|
212 |
+
progress(1.0, desc="Analysis complete!")
|
213 |
+
|
214 |
+
return (
|
215 |
+
gauge_chart,
|
216 |
+
breakdown_chart if breakdown_chart else gr.update(visible=False),
|
217 |
+
f"<div style='padding: 15px; background: rgba(0,0,0,0.1); border-radius: 10px; color: white;'>{highlighted_text}</div>",
|
218 |
+
analysis_report,
|
219 |
+
gr.update(visible=True)
|
220 |
+
)
|
221 |
+
|
222 |
+
def generate_analysis_report(threat_scores, overall_level, overall_score, detected_threats):
|
223 |
+
"""Generate detailed threat analysis report"""
|
224 |
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
225 |
+
|
226 |
+
report = f"""
|
227 |
+
## π Cybersecurity Threat Analysis Report
|
228 |
+
**Timestamp:** {timestamp}
|
229 |
+
**Overall Threat Level:** {overall_level.upper()} ({overall_score:.1%})
|
230 |
+
|
231 |
+
### π Summary
|
232 |
+
"""
|
233 |
+
|
234 |
+
if not threat_scores:
|
235 |
+
report += """
|
236 |
+
β
**No cybersecurity threats detected!**
|
237 |
+
|
238 |
+
The analyzed text appears to be safe and doesn't contain indicators of:
|
239 |
+
- Malware or malicious software
|
240 |
+
- Phishing attempts
|
241 |
+
- Social engineering tactics
|
242 |
+
- Data breach indicators
|
243 |
+
- Network attack patterns
|
244 |
+
- Advanced Persistent Threat (APT) activities
|
245 |
+
"""
|
246 |
+
else:
|
247 |
+
report += f"""
|
248 |
+
β οΈ **{len(detected_threats)} threat categories detected:**
|
249 |
+
|
250 |
+
"""
|
251 |
+
|
252 |
+
for threat_type, threat_info in threat_scores.items():
|
253 |
+
score_percent = threat_info["score"] * 100
|
254 |
+
keywords = ", ".join(f"`{kw}`" for kw in threat_info["keywords"])
|
255 |
+
|
256 |
+
report += f"""
|
257 |
+
**{threat_type.upper()}** - {score_percent:.1f}% confidence
|
258 |
+
- Detected keywords: {keywords}
|
259 |
+
|
260 |
+
"""
|
261 |
+
|
262 |
+
report += """
|
263 |
+
### π‘οΈ Recommendations
|
264 |
+
|
265 |
+
"""
|
266 |
+
|
267 |
+
if overall_level == "critical":
|
268 |
+
report += "π¨ **IMMEDIATE ACTION REQUIRED** - This content shows strong indicators of cybersecurity threats"
|
269 |
+
elif overall_level == "high":
|
270 |
+
report += "β οΈ **HIGH PRIORITY** - Review and investigate this content immediately"
|
271 |
+
elif overall_level == "medium":
|
272 |
+
report += "πΆ **MODERATE CONCERN** - Monitor and verify the source of this content"
|
273 |
+
else:
|
274 |
+
report += "π‘ **LOW PRIORITY** - Minor indicators detected, routine monitoring recommended"
|
275 |
+
|
276 |
+
return report
|
277 |
+
|
278 |
+
# Custom CSS for the interface
|
279 |
+
custom_css = """
|
280 |
+
.gradio-container {
|
281 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
|
282 |
+
color: white;
|
283 |
+
}
|
284 |
+
|
285 |
+
.gr-button {
|
286 |
+
background: linear-gradient(45deg, #FF6B6B, #4ECDC4) !important;
|
287 |
+
border: none !important;
|
288 |
+
color: white !important;
|
289 |
+
font-weight: bold !important;
|
290 |
+
transition: all 0.3s ease !important;
|
291 |
+
}
|
292 |
+
|
293 |
+
.gr-button:hover {
|
294 |
+
transform: translateY(-2px) !important;
|
295 |
+
box-shadow: 0 5px 15px rgba(0,0,0,0.3) !important;
|
296 |
+
}
|
297 |
+
|
298 |
+
.gr-textbox textarea {
|
299 |
+
background: rgba(255,255,255,0.1) !important;
|
300 |
+
border: 2px solid rgba(255,255,255,0.3) !important;
|
301 |
+
color: white !important;
|
302 |
+
}
|
303 |
+
|
304 |
+
.gr-markdown {
|
305 |
+
color: white !important;
|
306 |
+
}
|
307 |
+
|
308 |
+
.threat-highlight {
|
309 |
+
animation: pulse 2s infinite;
|
310 |
+
}
|
311 |
+
|
312 |
+
@keyframes pulse {
|
313 |
+
0% { opacity: 1; }
|
314 |
+
50% { opacity: 0.7; }
|
315 |
+
100% { opacity: 1; }
|
316 |
+
}
|
317 |
+
"""
|
318 |
+
|
319 |
+
# Build the Gradio interface
|
320 |
+
with gr.Blocks(css=custom_css, title="π¨ Cyber Threat Radar") as demo:
|
321 |
+
gr.Markdown("""
|
322 |
+
# π¨ Cyber Threat Radar Dashboard
|
323 |
+
### Powered by SecBERT - Real-time Cybersecurity Threat Detection
|
324 |
+
|
325 |
+
**Upload any text and watch our AI detect hidden cybersecurity threats in real-time!**
|
326 |
+
|
327 |
+
Try pasting emails, code snippets, news articles, or any suspicious content. Our advanced AI will analyze it for:
|
328 |
+
π¦ Malware indicators β’ π£ Phishing attempts β’ π₯ Social engineering β’ πΎ Data breaches β’ π Network attacks β’ π― APT activities
|
329 |
+
""")
|
330 |
+
|
331 |
+
with gr.Row():
|
332 |
+
with gr.Column(scale=2):
|
333 |
+
input_text = gr.Textbox(
|
334 |
+
label="π Enter text to analyze",
|
335 |
+
placeholder="Paste any text here - emails, articles, code, reports...",
|
336 |
+
lines=8,
|
337 |
+
max_lines=15
|
338 |
+
)
|
339 |
+
|
340 |
+
with gr.Row():
|
341 |
+
analyze_btn = gr.Button("π Analyze Threats", variant="primary", size="lg")
|
342 |
+
clear_btn = gr.Button("ποΈ Clear", variant="secondary")
|
343 |
+
|
344 |
+
gr.Markdown("### π― Try These Examples:")
|
345 |
+
example_buttons = []
|
346 |
+
for i, example in enumerate(DEMO_EXAMPLES):
|
347 |
+
btn = gr.Button(f"Example {i+1}: {example[:50]}...", variant="secondary", size="sm")
|
348 |
+
btn.click(lambda x=example: x, outputs=input_text)
|
349 |
+
example_buttons.append(btn)
|
350 |
+
|
351 |
+
with gr.Row():
|
352 |
+
with gr.Column():
|
353 |
+
threat_gauge = gr.Plot(label="π― Threat Level Gauge")
|
354 |
+
with gr.Column():
|
355 |
+
threat_breakdown = gr.Plot(label="π Threat Categories", visible=False)
|
356 |
+
|
357 |
+
with gr.Row():
|
358 |
+
highlighted_text = gr.HTML(label="π Text Analysis (Threats Highlighted)")
|
359 |
+
|
360 |
+
with gr.Row():
|
361 |
+
analysis_report = gr.Markdown(label="π Detailed Analysis Report")
|
362 |
+
|
363 |
+
results_section = gr.Group(visible=False)
|
364 |
+
|
365 |
+
# Event handlers
|
366 |
+
analyze_btn.click(
|
367 |
+
analyze_cybersecurity_threat,
|
368 |
+
inputs=[input_text],
|
369 |
+
outputs=[threat_gauge, threat_breakdown, highlighted_text, analysis_report, results_section]
|
370 |
+
)
|
371 |
+
|
372 |
+
clear_btn.click(
|
373 |
+
lambda: ("", None, None, "", gr.update(visible=False)),
|
374 |
+
outputs=[input_text, threat_gauge, threat_breakdown, analysis_report, results_section]
|
375 |
+
)
|
376 |
+
|
377 |
+
if __name__ == "__main__":
|
378 |
+
demo.launch(
|
379 |
+
share=True,
|
380 |
+
show_error=True,
|
381 |
+
debug=True,
|
382 |
+
server_name="0.0.0.0",
|
383 |
+
server_port=7860
|
384 |
+
)
|