Improved Summery Section

This commit is contained in:
BlackSnufkin
2025-01-04 14:12:31 -08:00
parent 35fe4c4e47
commit b85b2a0643
6 changed files with 503 additions and 25 deletions
+68 -25
View File
@@ -412,44 +412,87 @@ def register_routes(app):
@app.route('/file/<target>/<analysis_type>', methods=['GET'])
def get_analysis_results(target, analysis_type):
try:
# Find result folder for the given hash
result_path = find_file_by_hash(target, app.config['upload']['result_folder'])
if not result_path:
return jsonify({'error': 'Results not found'}), 404
return render_template('error.html', error='Results not found'), 404
# Load file info
file_info_path = os.path.join(result_path, 'file_info.json')
if not os.path.exists(file_info_path):
return render_template('error.html', error='File info not found'), 404
with open(file_info_path, 'r') as f:
file_info = json.load(f)
# Handle different types of requests
if analysis_type == 'info':
# Read and return the file info
file_info_path = os.path.join(result_path, 'file_info.json')
if not os.path.exists(file_info_path):
return jsonify({'error': 'File info not found'}), 404
with open(file_info_path, 'r') as f:
results = json.load(f)
return render_template('file_info.html', file_info=file_info)
elif analysis_type in ['static', 'dynamic']:
# Read and return the analysis results
results_file = f'{analysis_type}_analysis_results.json'
results_path = os.path.join(result_path, results_file)
if not os.path.exists(results_path):
return jsonify({'error': 'Analysis results not found'}), 404
return render_template('error.html', error=f'No {analysis_type} analysis results found'), 404
with open(results_path, 'r') as f:
results = json.load(f)
analysis_results = json.load(f)
else:
return jsonify({'error': 'Invalid analysis type'}), 400
if analysis_type == 'static':
# Calculate detection counts for static analysis with safe defaults
try:
yara_matches = analysis_results.get('yara', {}).get('matches', [])
yara_detections = len(yara_matches) if yara_matches is not None else 0
except:
yara_detections = 0
return jsonify({
'status': 'success',
'results': results
})
try:
checkplz_findings = analysis_results.get('checkplz', {}).get('findings', {})
checkplz_detections = 1 if checkplz_findings and checkplz_findings.get('initial_threat') else 0
except:
checkplz_detections = 0
# Format scan duration as MM:SS.mmm
try:
scan_duration = analysis_results.get('checkplz', {}).get('findings', {}).get('scan_results', {}).get('scan_duration', 0)
if scan_duration is None:
scan_duration = 0
minutes = int(scan_duration // 60)
seconds = int(scan_duration % 60)
milliseconds = int((scan_duration % 1) * 1000)
formatted_duration = f"{minutes:02d}:{seconds:02d}.{milliseconds:03d}"
except:
formatted_duration = "00:00.000"
return render_template('static_analysis.html',
file_info=file_info,
analysis_results=analysis_results,
yara_detections=yara_detections,
checkplz_detections=checkplz_detections,
scan_duration=formatted_duration)
elif analysis_type == 'dynamic':
# Calculate detection counts for dynamic analysis
yara_detections = len(analysis_results.get('yara', {}).get('matches', [])) if analysis_results.get('yara') else 0
pesieve_detections = analysis_results.get('pe_sieve', {}).get('findings', {}).get('total_suspicious', 0)
moneta_detections = (
analysis_results.get('moneta', {}).get('findings', {}).get('total_private_rwx', 0) +
analysis_results.get('moneta', {}).get('findings', {}).get('total_abnormal_private_exec', 0)
)
patriot_detections = len(analysis_results.get('patriot', {}).get('findings', {}).get('findings', []))
hsb_detections = analysis_results.get('hsb', {}).get('findings', {}).get('summary', {}).get('total_findings', 0)
return render_template('dynamic_analysis.html',
file_info=file_info,
analysis_results=analysis_results,
yara_detections=yara_detections,
pesieve_detections=pesieve_detections,
moneta_detections=moneta_detections,
patriot_detections=patriot_detections,
hsb_detections=hsb_detections)
return render_template('error.html', error='Invalid analysis type'), 400
except Exception as e:
return jsonify({
'status': 'error',
'error': str(e)
}), 500
return render_template('error.html', error=str(e)), 500
@app.route('/cleanup', methods=['POST'])
def cleanup():
Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

+139
View File
@@ -0,0 +1,139 @@
{% extends "base.html" %}
{% block content %}
<div class="max-w-6xl mx-auto px-4 py-6">
<!-- Header -->
<div class="flex items-center justify-between mb-6">
<div>
<h1 class="text-xl font-medium text-gray-100">Analysis Summary</h1>
<p class="text-base text-gray-500 mb-6">Comprehensive overview of all scan results.</p>
</div>
<button onclick="window.location.href='/file/{{ file_info.md5 }}/info'"
class="px-4 py-2 bg-gray-500/10 text-gray-400 border border-gray-800 rounded-lg hover:bg-gray-500/20 transition-colors">
Back to File Info
</button>
</div>
<!-- Target Details -->
<div id="targetDetails" class="mb-6">
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4 mb-4">
<h4 class="text-base font-medium text-gray-100 mb-2">Target Process</h4>
{% if analysis_results.moneta and analysis_results.moneta.findings.process_info %}
{% set info = analysis_results.moneta.findings.process_info %}
<p class="text-gray-300">
<span class="font-semibold">Name:</span> {{ info.name }}<br>
<span class="font-semibold">PID:</span> {{ info.pid }}<br>
<span class="font-semibold">Path:</span> <span class="text-gray-400">{{ info.path }}</span>
</p>
{% endif %}
</div>
</div>
<!-- Overall Status Grid -->
<div class="grid grid-cols-3 gap-4 mb-6">
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4">
<div class="text-sm text-gray-500">Overall Status</div>
<div id="overallStatus" class="text-2xl font-semibold {{ 'text-red-500' if yara_detections + pesieve_detections + moneta_detections + patriot_detections + hsb_detections > 0 else 'text-green-500' }}">
{{ 'Threats Detected' if yara_detections + pesieve_detections + moneta_detections + patriot_detections + hsb_detections > 0 else 'Clean' }}
</div>
</div>
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4">
<div class="text-sm text-gray-500">Total Detections</div>
<div id="totalDetections" class="text-2xl font-semibold text-gray-300">{{ yara_detections + pesieve_detections + moneta_detections + patriot_detections + hsb_detections }}</div>
</div>
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4">
<div class="text-sm text-gray-500">Scan Duration</div>
<div id="scanDuration" class="text-2xl font-semibold text-gray-300">
{{ "%.2f"|format(analysis_results.moneta.findings.scan_duration if analysis_results.moneta else 0) }}s
</div>
</div>
</div>
<!-- Scanner Results Table -->
<div class="bg-gray-900/30 rounded-lg border border-gray-800 overflow-hidden">
<table class="w-full">
<thead>
<tr class="border-b border-gray-800">
<th class="px-6 py-3 text-left text-base font-medium text-gray-300">Scanner</th>
<th class="px-6 py-3 text-left text-base font-medium text-gray-300">Status</th>
<th class="px-6 py-3 text-left text-base font-medium text-gray-300">Detections</th>
<th class="px-6 py-3 text-left text-base font-medium text-gray-300">Details</th>
</tr>
</thead>
<tbody id="scannerResultsBody" class="divide-y divide-gray-800">
<!-- YARA Results Row -->
<tr>
<td class="px-6 py-4 text-base text-gray-300">YARA</td>
<td class="px-6 py-4">
<span class="px-2 py-1 text-base rounded {{ 'bg-red-500/10 text-red-500' if yara_detections else 'bg-green-500/10 text-green-500' }}">
{{ 'Suspicious' if yara_detections else 'Clean' }}
</span>
</td>
<td class="px-6 py-4 text-base {{ 'text-red-500' if yara_detections else 'text-gray-400' }}">{{ yara_detections }}</td>
<td class="px-6 py-4 text-base text-gray-400">
{{ yara_detections|string + ' rule matches found' if yara_detections else 'No threats detected' }}
</td>
</tr>
<!-- PE-sieve Results Row -->
<tr>
<td class="px-6 py-4 text-base text-gray-300">PE-sieve</td>
<td class="px-6 py-4">
<span class="px-2 py-1 text-base rounded {{ 'bg-red-500/10 text-red-500' if pesieve_detections else 'bg-green-500/10 text-green-500' }}">
{{ 'Suspicious' if pesieve_detections else 'Clean' }}
</span>
</td>
<td class="px-6 py-4 text-base {{ 'text-red-500' if pesieve_detections else 'text-gray-400' }}">{{ pesieve_detections }}</td>
<td class="px-6 py-4 text-base text-gray-400">
{{ pesieve_detections|string + ' suspicious modifications found' if pesieve_detections else 'No modifications detected' }}
</td>
</tr>
<!-- Moneta Results Row -->
<tr>
<td class="px-6 py-4 text-base text-gray-300">Moneta</td>
<td class="px-6 py-4">
<span class="px-2 py-1 text-base rounded {{ 'bg-red-500/10 text-red-500' if moneta_detections else 'bg-green-500/10 text-green-500' }}">
{{ 'Suspicious' if moneta_detections else 'Clean' }}
</span>
</td>
<td class="px-6 py-4 text-base {{ 'text-red-500' if moneta_detections else 'text-gray-400' }}">{{ moneta_detections }}</td>
<td class="px-6 py-4 text-base text-gray-400">
{{ 'Memory anomalies found' if moneta_detections else 'No anomalies detected' }}
</td>
</tr>
<!-- Patriot Results Row -->
<tr>
<td class="px-6 py-4 text-base text-gray-300">Patriot</td>
<td class="px-6 py-4">
<span class="px-2 py-1 text-base rounded {{ 'bg-red-500/10 text-red-500' if patriot_detections else 'bg-green-500/10 text-green-500' }}">
{{ 'Suspicious' if patriot_detections else 'Clean' }}
</span>
</td>
<td class="px-6 py-4 text-base {{ 'text-red-500' if patriot_detections else 'text-gray-400' }}">{{ patriot_detections }}</td>
<td class="px-6 py-4 text-base text-gray-400">
{{ patriot_detections|string + ' suspicious activities found' if patriot_detections else 'No suspicious activities' }}
</td>
</tr>
<!-- HSB Results Row -->
<tr>
<td class="px-6 py-4 text-base text-gray-300">Hunt-Sleeping-Beacons</td>
<td class="px-6 py-4">
<span class="px-2 py-1 text-base rounded {{ 'bg-red-500/10 text-red-500' if hsb_detections else 'bg-green-500/10 text-green-500' }}">
{{ 'Suspicious' if hsb_detections else 'Clean' }}
</span>
</td>
<td class="px-6 py-4 text-base {{ 'text-red-500' if hsb_detections else 'text-gray-400' }}">{{ hsb_detections }}</td>
<td class="px-6 py-4 text-base text-gray-400">
{{ 'Suspicious behavior detected' if hsb_detections else 'No suspicious behavior' }}
</td>
</tr>
</tbody>
</table>
</div>
<!-- Rest of your existing detailed results code here -->
</div>
{% endblock %}
+38
View File
@@ -0,0 +1,38 @@
{% extends "base.html" %}
{% block content %}
<div class="max-w-6xl mx-auto px-4 py-12 min-h-[80vh] flex items-center justify-center">
<div class="text-center">
<!-- Error Icon -->
<div class="mb-6">
<svg class="w-20 h-20 text-red-500 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
</svg>
</div>
<!-- Error Message -->
<h1 class="text-2xl font-medium text-gray-100 mb-3">Something went wrong</h1>
<p class="text-gray-400 mb-6">{{ error }}</p>
<!-- Navigation Buttons -->
<div class="flex items-center justify-center gap-4">
<button onclick="history.back()"
class="px-4 py-2 bg-gray-500/10 text-gray-300 border border-gray-800 rounded-lg hover:bg-gray-500/20 transition-colors flex items-center gap-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 15l-3-3m0 0l3-3m-3 3h8M3 12a9 9 0 1118 0 9 9 0 01-18 0z"/>
</svg>
<span>Go Back</span>
</button>
<button onclick="window.location.href='/'"
class="px-4 py-2 bg-red-500/10 text-red-400 border border-red-900/20 rounded-lg hover:bg-red-500/20 transition-colors flex items-center gap-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
</svg>
<span>Go Home</span>
</button>
</div>
</div>
</div>
{% endblock %}
+166
View File
@@ -0,0 +1,166 @@
{% extends "base.html" %}
{% block content %}
<div class="max-w-6xl mx-auto px-4 py-6">
<!-- Header -->
<div class="flex items-center justify-between mb-6">
<div>
<h1 class="text-2xl font-medium text-gray-100">{{ file_info.original_name }}</h1>
<p class="text-base text-gray-400 mt-1 font-mono">MD5: {{ file_info.md5 }}</p>
</div>
<span class="px-3 py-1 rounded-lg text-sm font-medium
{% if file_info.entropy_analysis.detection_risk == 'High' %}
bg-red-500 text-white
{% elif file_info.entropy_analysis.detection_risk == 'Medium' %}
bg-yellow-500 text-black
{% else %}
bg-green-500 text-white
{% endif %}">
{{ file_info.entropy_analysis.detection_risk }} Risk
</span>
</div>
<!-- Add this after the header div -->
<div class="flex items-center gap-4 mb-6">
<button onclick="window.location.href='/file/{{ file_info.md5 }}/static'"
class="px-4 py-2 bg-blue-500/10 text-blue-400 border border-blue-900/20 rounded-lg hover:bg-blue-500/20 transition-colors flex items-center gap-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"/>
</svg>
<span>Static Analysis Results</span>
</button>
<button onclick="window.location.href='/file/{{ file_info.md5 }}/dynamic'"
class="px-4 py-2 bg-green-500/10 text-green-400 border border-green-900/20 rounded-lg hover:bg-green-500/20 transition-colors flex items-center gap-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
</svg>
<span>Dynamic Analysis Results</span>
</button>
</div>
<!-- Basic Info Card -->
<div class="bg-black/60 backdrop-blur-sm rounded-xl border border-gray-800 p-6 mb-6">
<h2 class="text-lg font-medium text-gray-100 mb-4">Basic Information</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div>
<p class="text-sm text-gray-400">File Size</p>
<p class="text-gray-200">{{ file_info.size|filesizeformat }}</p>
</div>
<div>
<p class="text-sm text-gray-400">File Type</p>
<p class="text-gray-200">{{ file_info.mime_type }}</p>
</div>
<div>
<p class="text-sm text-gray-400">Upload Time</p>
<p class="text-gray-200">{{ file_info.upload_time }}</p>
</div>
<div>
<p class="text-sm text-gray-400">SHA256</p>
<p class="text-gray-200 font-mono text-sm break-all">{{ file_info.sha256 }}</p>
</div>
<div>
<p class="text-sm text-gray-400">Entropy</p>
<p class="text-gray-200">{{ "%.2f"|format(file_info.entropy) }}</p>
</div>
</div>
</div>
{% if file_info.pe_info %}
<!-- PE Info -->
<div class="bg-black/60 backdrop-blur-sm rounded-xl border border-gray-800 p-6 mb-6">
<h2 class="text-lg font-medium text-gray-100 mb-4">PE Information</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div>
<p class="text-sm text-gray-400">File Type</p>
<p class="text-gray-200">{{ file_info.pe_info.file_type }}</p>
</div>
<div>
<p class="text-sm text-gray-400">Machine Type</p>
<p class="text-gray-200">{{ file_info.pe_info.machine_type }}</p>
</div>
<div>
<p class="text-sm text-gray-400">Subsystem</p>
<p class="text-gray-200">{{ file_info.pe_info.subsystem }}</p>
</div>
<div>
<p class="text-sm text-gray-400">Compile Time</p>
<p class="text-gray-200">{{ file_info.pe_info.compile_time }}</p>
</div>
<div>
<p class="text-sm text-gray-400">Entry Point</p>
<p class="text-gray-200 font-mono">{{ file_info.pe_info.entry_point }}</p>
</div>
</div>
</div>
<!-- Detection Notes -->
<div class="bg-black/60 backdrop-blur-sm rounded-xl border border-gray-800 p-6 mb-6">
<h2 class="text-lg font-medium text-gray-100 mb-4">Detection Notes</h2>
<ul class="space-y-2">
{% for note in file_info.pe_info.detection_notes %}
<li class="flex items-start gap-2">
<svg class="w-5 h-5 text-red-500 mt-0.5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
</svg>
<span class="text-gray-300">{{ note }}</span>
</li>
{% endfor %}
</ul>
</div>
<!-- PE Sections -->
<div class="bg-black/60 backdrop-blur-sm rounded-xl border border-gray-800 p-6 mb-6">
<h2 class="text-lg font-medium text-gray-100 mb-4">PE Sections</h2>
<div class="overflow-x-auto">
<table class="w-full">
<thead>
<tr class="border-b border-gray-800">
<th class="text-left py-3 text-gray-400">Name</th>
<th class="text-left py-3 text-gray-400">Size</th>
<th class="text-left py-3 text-gray-400">Entropy</th>
<th class="text-left py-3 text-gray-400">Notes</th>
</tr>
</thead>
<tbody>
{% for section in file_info.pe_info.sections %}
<tr class="border-b border-gray-800">
<td class="py-3">
<span class="font-mono {% if section.is_standard %}text-gray-300{% else %}text-yellow-500{% endif %}">
{{ section.name }}
</span>
</td>
<td class="py-3 text-gray-300">{{ section.size|filesizeformat }}</td>
<td class="py-3">
<span class="{% if section.entropy > 7.2 %}text-red-500{% else %}text-gray-300{% endif %}">
{{ "%.2f"|format(section.entropy) }}
</span>
</td>
<td class="py-3">
<div class="space-y-1">
{% for note in section.detection_notes %}
<div class="text-sm text-red-400">{{ note }}</div>
{% endfor %}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Suspicious Imports -->
{% if file_info.pe_info.suspicious_imports %}
<div class="bg-black/60 backdrop-blur-sm rounded-xl border border-gray-800 p-6">
<h2 class="text-lg font-medium text-gray-100 mb-4">Suspicious Imports</h2>
<div class="space-y-4">
{% for import in file_info.pe_info.suspicious_imports %}
<div class="p-4 bg-red-500/10 rounded-lg border border-red-900/20">
<p class="text-red-400 font-mono">{{ import.dll }}!{{ import.function }}</p>
<p class="text-sm text-gray-400 mt-1">{{ import.note }}</p>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% endif %}
</div>
{% endblock %}
+92
View File
@@ -0,0 +1,92 @@
{% extends "base.html" %}
{% block content %}
<div class="max-w-6xl mx-auto px-4 py-6">
<!-- Header -->
<div class="flex items-center justify-between mb-6">
<div>
<h1 class="text-xl font-medium text-gray-100">Analysis Summary</h1>
<p class="text-base text-gray-500 mb-6">Comprehensive overview of all scan results.</p>
</div>
<button onclick="window.location.href='/file/{{ file_info.md5 }}/info'"
class="px-4 py-2 bg-gray-500/10 text-gray-400 border border-gray-800 rounded-lg hover:bg-gray-500/20 transition-colors">
Back to File Info
</button>
</div>
<!-- Target Details -->
<div id="targetDetails" class="mb-6">
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4 mb-4">
<h4 class="text-base font-medium text-gray-100 mb-2">Target File</h4>
<p class="text-gray-300">
<span class="font-semibold">File Path:</span>
{{ analysis_results.checkplz.findings.scan_results.file_path if analysis_results.checkplz else file_info.original_name }}
</p>
</div>
</div>
<!-- Overall Status Grid -->
<div class="grid grid-cols-3 gap-4 mb-6">
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4">
<div class="text-sm text-gray-500">Overall Status</div>
<div id="overallStatus" class="text-2xl font-semibold {{ 'text-red-500' if yara_detections or checkplz_detections else 'text-green-500' }}">
{{ 'Threats Detected' if yara_detections or checkplz_detections else 'Clean' }}
</div>
</div>
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4">
<div class="text-sm text-gray-500">Total Detections</div>
<div id="totalDetections" class="text-2xl font-semibold text-gray-300">{{ yara_detections + checkplz_detections }}</div>
</div>
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4">
<div class="text-sm text-gray-500">Scan Duration</div>
<div class="text-2xl font-semibold text-gray-300">
{{ scan_duration }}
</div>
</div>
</div>
<!-- Scanner Results Table -->
<div class="bg-gray-900/30 rounded-lg border border-gray-800 overflow-hidden">
<table class="w-full">
<thead>
<tr class="border-b border-gray-800">
<th class="px-6 py-3 text-left text-base font-medium text-gray-300">Scanner</th>
<th class="px-6 py-3 text-left text-base font-medium text-gray-300">Status</th>
<th class="px-6 py-3 text-left text-base font-medium text-gray-300">Detections</th>
<th class="px-6 py-3 text-left text-base font-medium text-gray-300">Details</th>
</tr>
</thead>
<tbody id="scannerResultsBody" class="divide-y divide-gray-800">
<!-- YARA Results Row -->
<tr>
<td class="px-6 py-4 text-base text-gray-300">YARA</td>
<td class="px-6 py-4">
<span class="px-2 py-1 text-base rounded {{ 'bg-red-500/10 text-red-500' if yara_detections else 'bg-green-500/10 text-green-500' }}">
{{ 'Suspicious' if yara_detections else 'Clean' }}
</span>
</td>
<td class="px-6 py-4 text-base {{ 'text-red-500' if yara_detections else 'text-gray-400' }}">{{ yara_detections }}</td>
<td class="px-6 py-4 text-base text-gray-400">
{{ yara_detections|string + ' rule matches found' if yara_detections else 'No threats detected' }}
</td>
</tr>
<!-- CheckPlz Results Row -->
<tr>
<td class="px-6 py-4 text-base text-gray-300">CheckPlz</td>
<td class="px-6 py-4">
<span class="px-2 py-1 text-base rounded {{ 'bg-red-500/10 text-red-500' if checkplz_detections else 'bg-green-500/10 text-green-500' }}">
{{ 'Suspicious' if checkplz_detections else 'Clean' }}
</span>
</td>
<td class="px-6 py-4 text-base {{ 'text-red-500' if checkplz_detections else 'text-gray-400' }}">{{ checkplz_detections }}</td>
<td class="px-6 py-4 text-base text-gray-400">
{{ analysis_results.checkplz.findings.initial_threat if checkplz_detections else 'No threats detected' }}
</td>
</tr>
</tbody>
</table>
</div>
<!-- Rest of your existing detailed results code here -->
</div>
{% endblock %}