Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: "Cloudflare Insights"
toc_hide: true
---

Import Cloudflare Insights findings using the **CSV export** provided by Cloudflare.

### Sample Scan Data
Sample Cloudflare Insights files can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/cloudflare_insights).

### Supported Fields
The parser supports the following CSV columns:

- `severity`
- `issue_class`
- `subject`
- `issue_type`
- `status`
- `insight` *(optional)*
- `detection_method` *(optional)*
- `risk` *(optional)*
- `recommended_action`
Empty file.
128 changes: 128 additions & 0 deletions dojo/tools/cloudflare_insights/parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import csv
import io
from urllib.parse import urlparse

from dojo.models import Endpoint, Finding


class CloudflareInsightsParser:

"""
DefectDojo parser for Cloudflare Insights CSV exports.

Expected columns:
- severity
- issue_class
- subject (used as Endpoint host; not repeated in description)
- issue_type
- scan_performed_on (ignored)
- status
- insight (optional)
- detection_method (optional)
- risk (optional)
- recommended_action (used as mitigation if present)
"""

def get_scan_types(self):
return ["Cloudflare Insights"]

def get_label_for_scan_types(self, scan_type):
return scan_type

def get_description_for_scan_types(self, scan_type):
return "Import Cloudflare Insights (CSV export)."

def _map_severity(self, value):
normalized = value.strip().lower()
mapping = {
"low": "Low",
"moderate": "Medium",
"critical": "Critical",
"high": "High", # optional: Cloudflare occasionally uses this
}
return mapping.get(normalized, "Info")

def _extract_host_from_subject(self, subject: str) -> str | None:
if not subject:
return None
s = subject.strip()
if not s:
return None
parsed = urlparse(s)
netloc = parsed.netloc
if not netloc and ("." in s or ":" in s or s.startswith("localhost")):
parsed2 = urlparse(f"http://{s}")
netloc = parsed2.netloc
host = netloc or s
if ":" in host:
host = host.split(":", 1)[0]
host = host.strip().strip("/").strip()

return host or None

def _is_inactive_status(self, status: str) -> bool:
inactive_markers = {"resolved", "mitigated", "closed", "fixed"}
return bool(status) and status.strip().lower() in inactive_markers

def get_findings(self, filename, test):
content = filename.read()
if isinstance(content, bytes):
content = content.decode("utf-8", errors="replace")

reader = csv.DictReader(
io.StringIO(content),
delimiter=",",
quotechar='"',
skipinitialspace=True,
)
findings = []
for row in reader:
severity_raw = (row.get("severity") or "").strip()
issue_class = (row.get("issue_class") or "").strip()
subject = (row.get("subject") or "").strip()
issue_type = (row.get("issue_type") or "").strip()
status = (row.get("status") or "").strip()
insight = (row.get("insight") or "").strip()
detection_method = (row.get("detection_method") or "").strip()
risk = (row.get("risk") or "").strip()
recommended_action = (row.get("recommended_action") or "").strip()
mapped_severity = self._map_severity(severity_raw)
if issue_type and subject:
title = f"{issue_type}: {subject}"
elif issue_type:
title = issue_type
elif subject:
title = subject
else:
title = "Cloudflare Insight"
description_parts = []
if issue_class:
description_parts.append(f"**Issue class**: {issue_class}")
if issue_type:
description_parts.append(f"**Issue type**: {issue_type}")
if status:
description_parts.append(f"**Status**: {status}")
if insight:
description_parts.append(f"**Insight**: {insight}")
if detection_method:
description_parts.append(f"**Detection method**: {detection_method}")
if risk:
description_parts.append(f"**Risk**: {risk}")
description = "\n\n".join(description_parts)
finding = Finding(
test=test,
title=title,
severity=mapped_severity,
description=description,
mitigation=recommended_action,
references="Not provided!",
static_finding=False,
dynamic_finding=True,
)
finding.active = not self._is_inactive_status(status)
host = self._extract_host_from_subject(subject)
if host:
finding.unsaved_endpoints = [Endpoint(host=host, port=None)]
findings.append(finding)

return findings
15 changes: 15 additions & 0 deletions unittests/scans/cloudflare_insights/many_findings.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
severity,issue_class,subject,issue_type,scan_performed_on,status,insight,detection_method,risk,recommended_action
Moderate,Unproxied 'A' Records,domain1.com,Exposed infrastructure,2024-07-05T05:30:57.976844Z,Active,,,,"Configure Cloudflare to proxy the DNS record. By setting up Cloudflare as your hostname's reverse proxy, Cloudflare protects origin servers from DDoS attacks by hiding their IP addresses. You can configure Cloudflare to proxy your hostname in your DNS settings."
Moderate,Unproxied 'A' Records,domain2.com,Exposed infrastructure,2024-07-05T05:31:39.692808Z,Active,,,,"Configure Cloudflare to proxy the DNS record. By setting up Cloudflare as your hostname's reverse proxy, Cloudflare protects origin servers from DDoS attacks by hiding their IP addresses. You can configure Cloudflare to proxy your hostname in your DNS settings."
Low,Security.txt not configured,domain3.com,Configuration suggestion,2024-12-01T05:43:45.712676Z,Active,Security.txt not configured. Configure and manage the Security.txt file to improve the website's vulnerability disclosure process,We evaluated the Security Settings configured for this domain and found that Security.txt is not enabled.,"The absence of Security.txt insights creates a lack of a clear, accessible method for researchers to report vulnerabilities. This can lead to security issues going unnoticed or under-reported, increasing the risk of exploitation.","Configure Security.txt file. "
Low,Security.txt not configured,domain4.com,Configuration suggestion,2024-12-01T05:43:44.252529Z,Active,Security.txt not configured. Configure and manage the Security.txt file to improve the website's vulnerability disclosure process,We evaluated the Security Settings configured for this domain and found that Security.txt is not enabled.,"The absence of Security.txt insights creates a lack of a clear, accessible method for researchers to report vulnerabilities. This can lead to security issues going unnoticed or under-reported, increasing the risk of exploitation.","Configure Security.txt file. "
Moderate,Unproxied CNAME Records,domain5.com,Exposed infrastructure,2024-07-08T03:37:16.031911Z,Active,,,,"Configure Cloudflare to proxy the DNS record. By setting up Cloudflare as your hostname's reverse proxy, Cloudflare protects origin servers from DDoS attacks by hiding their IP addresses. You can configure Cloudflare to proxy your hostname in your DNS settings."
Moderate,Unproxied 'A' Records,domain6.com,Exposed infrastructure,2024-07-02T12:55:57.798974Z,Active,,,,"Configure Cloudflare to proxy the DNS record. By setting up Cloudflare as your hostname's reverse proxy, Cloudflare protects origin servers from DDoS attacks by hiding their IP addresses. You can configure Cloudflare to proxy your hostname in your DNS settings."
Low,Security.txt not configured,domain7.com,Configuration suggestion,2025-03-25T17:33:40.070204Z,Active,Security.txt not configured. Configure and manage the Security.txt file to improve the website's vulnerability disclosure process,We evaluated the Security Settings configured for this domain and found that Security.txt is not enabled.,"The absence of Security.txt insights creates a lack of a clear, accessible method for researchers to report vulnerabilities. This can lead to security issues going unnoticed or under-reported, increasing the risk of exploitation.","Configure Security.txt file. "
Low,Security.txt not configured,domain8.com,Configuration suggestion,2025-03-25T17:33:41.970652Z,Active,Security.txt not configured. Configure and manage the Security.txt file to improve the website's vulnerability disclosure process,We evaluated the Security Settings configured for this domain and found that Security.txt is not enabled.,"The absence of Security.txt insights creates a lack of a clear, accessible method for researchers to report vulnerabilities. This can lead to security issues going unnoticed or under-reported, increasing the risk of exploitation.","Configure Security.txt file. "
Moderate,Unproxied 'A' Records,domain9.com,Exposed infrastructure,2024-07-05T05:30:46.435059Z,Active,,,,"Configure Cloudflare to proxy the DNS record. By setting up Cloudflare as your hostname's reverse proxy, Cloudflare protects origin servers from DDoS attacks by hiding their IP addresses. You can configure Cloudflare to proxy your hostname in your DNS settings."
Low,Security.txt not configured,domain10.com,Configuration suggestion,2024-11-29T05:32:39.671608Z,Active,Security.txt not configured. Configure and manage the Security.txt file to improve the website's vulnerability disclosure process,We evaluated the Security Settings configured for this domain and found that Security.txt is not enabled.,"The absence of Security.txt insights creates a lack of a clear, accessible method for researchers to report vulnerabilities. This can lead to security issues going unnoticed or under-reported, increasing the risk of exploitation.","Configure Security.txt file. "
Low,Security.txt not configured,domain11.com,Configuration suggestion,2025-03-06T15:16:53.931468Z,Active,Security.txt not configured. Configure and manage the Security.txt file to improve the website's vulnerability disclosure process,We evaluated the Security Settings configured for this domain and found that Security.txt is not enabled.,"The absence of Security.txt insights creates a lack of a clear, accessible method for researchers to report vulnerabilities. This can lead to security issues going unnoticed or under-reported, increasing the risk of exploitation.","Configure Security.txt file. "
Moderate,Unproxied CNAME Records,domain12.com,Exposed infrastructure,2026-01-02T12:29:43.13416Z,Active,Unproxied CNAME Records. This DNS record is not proxied by Cloudflare. Your origin server is directly exposed and has a higher risk of a DDoS attack.,We reviewed your Cloudflare DNS settings and checked whether your hostname accepts connections on either port 80 or 443.,DDoS Attack,"Configure Cloudflare to proxy the DNS record. By setting up Cloudflare as your hostname's reverse proxy, Cloudflare protects origin servers from DDoS attacks by hiding their IP addresses. You can configure Cloudflare to proxy your hostname in your DNS settings."
Moderate,Unproxied 'A' Records,domain13.com,Exposed infrastructure,2024-07-02T12:57:30.878124Z,Active,,,,"Configure Cloudflare to proxy the DNS record. By setting up Cloudflare as your hostname's reverse proxy, Cloudflare protects origin servers from DDoS attacks by hiding their IP addresses. You can configure Cloudflare to proxy your hostname in your DNS settings."
Critical,Managed Rules not deployed,domain14.com,Configuration suggestion,2024-07-01T17:44:27.896818Z,Active,Managed Rules not deployed. We have detected that you have not enabled the Cloudflare Managed Rules feature on your zone.,We evaluated your websites and you have no Managed Rules deployed.,Insufficient protection for vulnerabilities targeting Web and API applications,Turn on Managed Rules. Deploy Cloudflare Managed Rules on your zone to protect your web application against common vulnerabilities in web applications.
2 changes: 2 additions & 0 deletions unittests/scans/cloudflare_insights/one_finding.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
severity,issue_class,subject,issue_type,scan_performed_on,status,insight,detection_method,risk,recommended_action
Moderate,Unproxied 'A' Records,domain.com,Exposed infrastructure,2024-07-06T13:50:15.536086Z,Active,,,,"Configure Cloudflare to proxy the DNS record. By setting up Cloudflare as your hostname's reverse proxy, Cloudflare protects origin servers from DDoS attacks by hiding their IP addresses. You can configure Cloudflare to proxy your hostname in your DNS settings."
24 changes: 24 additions & 0 deletions unittests/tools/test_cloudflare_insights_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from dojo.models import Test
from dojo.tools.cloudflare_insights.parser import CloudflareInsightsParser
from unittests.dojo_test_case import DojoTestCase, get_unit_tests_scans_path


class TestCloudflareInsightsParser(DojoTestCase):

def test_cloudflare_insights_parser_with_one_finding(self):
with (get_unit_tests_scans_path("cloudflare_insights") / "one_finding.csv").open(encoding="utf-8") as testfile:
parser = CloudflareInsightsParser()
findings = parser.get_findings(testfile, Test())
self.assertEqual(1, len(findings))
finding = findings[0]
self.assertEqual("Exposed infrastructure: domain.com", finding.title)
self.assertEqual("Medium", finding.severity)

def test_cloudflare_insights_parser_with_many_findings(self):
with (get_unit_tests_scans_path("cloudflare_insights") / "many_findings.csv").open(encoding="utf-8") as testfile:
parser = CloudflareInsightsParser()
findings = parser.get_findings(testfile, Test())
self.assertEqual(14, len(findings))
finding = findings[0]
self.assertEqual("Exposed infrastructure: domain1.com", finding.title)
self.assertEqual("Medium", finding.severity)