diff --git a/website/templates/organization/organization_analytics.html b/website/templates/organization/organization_analytics.html
index bf1f2f1575..0b58b85483 100644
--- a/website/templates/organization/organization_analytics.html
+++ b/website/templates/organization/organization_analytics.html
@@ -327,6 +327,51 @@
Top Affected Domains
+
+
+
+
Threat Intelligence
+
+
+
+
Security Risk Score
+
+
+
+
+ {{ threat_intelligence.risk_score }}/100
+
+
+
+
+
+
+
+
Top Issue Categories
+
+ {% for vector in threat_intelligence.attack_vectors %}
+
+ {{ vector.vulnerability_type }}
+ {{ vector.count }}
+
+ {% endfor %}
+
+
+
+
+
Recent Security Alerts
+
+ {% for alert in threat_intelligence.recent_alerts %}
+
+
+ {{ alert.description }}
+
+ {% endfor %}
+
+
+
+
+
{% endblock body %}
{% block js %}
diff --git a/website/views/company.py b/website/views/company.py
index c3ba42b341..ee87e31fbf 100644
--- a/website/views/company.py
+++ b/website/views/company.py
@@ -225,6 +225,45 @@ def get_security_incidents_summary(self, organization):
.order_by("-count")[:5],
}
+ def get_threat_intelligence(self, organization):
+ """Gets threat intelligence data for the organization."""
+ security_issues = Issue.objects.filter(
+ domain__organization__id=organization,
+ label=4, # Security label
+ )
+
+ # Get trending attack types based on issue labels/tags instead
+ attack_vectors = (
+ security_issues.filter(created__gte=timezone.now() - timedelta(days=90))
+ .values("label") # Use label instead of vulnerability_type
+ .annotate(count=Count("id"))
+ .order_by("-count")[:5]
+ )
+
+ # Calculate risk score (0-100)
+ total_issues = security_issues.count()
+ critical_issues = security_issues.filter(cve_score__gte=8).count() # Use cve_score instead of severity
+ risk_score = min(100, (critical_issues / total_issues * 100) if total_issues > 0 else 0)
+
+ return {
+ "attack_vectors": [
+ {
+ "vulnerability_type": self.get_label_name(vector["label"]), # Convert label to readable name
+ "count": vector["count"],
+ }
+ for vector in attack_vectors
+ ],
+ "risk_score": int(risk_score),
+ "recent_alerts": security_issues.filter(
+ created__gte=timezone.now() - timedelta(days=7),
+ cve_score__gte=7, # Use cve_score for severity
+ ).order_by("-created")[:5],
+ }
+
+ def get_label_name(self, label_id):
+ """Convert label ID to human-readable name."""
+ return self.labels.get(label_id, "Other")
+
def get_general_info(self, organization):
total_organization_bugs = Issue.objects.filter(domain__organization__id=organization).count()
total_bug_hunts = Hunt.objects.filter(domain__organization__id=organization).count()
@@ -413,6 +452,7 @@ def get(self, request, id, *args, **kwargs):
"spent_on_bugtypes": self.get_spent_on_bugtypes(id),
"security_incidents_summary": self.get_security_incidents_summary(id),
}
+ context.update({"threat_intelligence": self.get_threat_intelligence(id)})
return render(request, "organization/organization_analytics.html", context=context)