Spaces:
Sleeping
Sleeping
Update header_analyzer.py
Browse files- header_analyzer.py +29 -16
header_analyzer.py
CHANGED
|
@@ -3,40 +3,53 @@ import re
|
|
| 3 |
def analyze_headers(headers):
|
| 4 |
findings = []
|
| 5 |
score = 0
|
|
|
|
| 6 |
|
| 7 |
-
#
|
| 8 |
-
auth_results = headers.get("Authentication-Results"
|
| 9 |
-
if "dkim=fail" in auth_results
|
| 10 |
findings.append("Header: DKIM check failed")
|
| 11 |
score += 25
|
| 12 |
-
if "spf=fail" in auth_results
|
| 13 |
findings.append("Header: SPF check failed")
|
| 14 |
score += 25
|
| 15 |
-
if "dmarc=fail" in auth_results
|
| 16 |
findings.append("Header: DMARC check failed")
|
| 17 |
score += 25
|
| 18 |
|
| 19 |
-
#
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
|
|
|
| 25 |
|
| 26 |
-
#
|
| 27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
match = re.search(r'@([a-zA-Z0-9.-]+)', sender)
|
| 29 |
if match:
|
| 30 |
domain = match.group(1).lower()
|
|
|
|
| 31 |
if any(free in domain for free in ["gmail.com", "yahoo.com", "outlook.com"]):
|
| 32 |
findings.append(f"Header: Free email provider used ({domain})")
|
| 33 |
score += 10
|
| 34 |
-
if len(
|
| 35 |
findings.append(f"Header: Suspicious-looking domain ({domain})")
|
| 36 |
score += 15
|
| 37 |
|
| 38 |
-
#
|
| 39 |
-
if "
|
| 40 |
findings.append("Header: Email sent with BCC (common in mass phishing)")
|
| 41 |
score += 15
|
| 42 |
|
|
|
|
| 3 |
def analyze_headers(headers):
|
| 4 |
findings = []
|
| 5 |
score = 0
|
| 6 |
+
headers = headers or {}
|
| 7 |
|
| 8 |
+
# 1) SPF / DKIM / DMARC
|
| 9 |
+
auth_results = (headers.get("Authentication-Results") or "").lower()
|
| 10 |
+
if "dkim=fail" in auth_results or "dkim=permerror" in auth_results:
|
| 11 |
findings.append("Header: DKIM check failed")
|
| 12 |
score += 25
|
| 13 |
+
if "spf=fail" in auth_results:
|
| 14 |
findings.append("Header: SPF check failed")
|
| 15 |
score += 25
|
| 16 |
+
if "dmarc=fail" in auth_results:
|
| 17 |
findings.append("Header: DMARC check failed")
|
| 18 |
score += 25
|
| 19 |
|
| 20 |
+
# softer signals
|
| 21 |
+
if any(x in auth_results for x in ["spf=softfail", "spf=neutral", "spf=none"]):
|
| 22 |
+
findings.append("Header: SPF not properly aligned")
|
| 23 |
+
score += 10
|
| 24 |
+
if any(x in auth_results for x in ["dmarc=temperror", "dkim=temperror"]):
|
| 25 |
+
findings.append("Header: Temporary auth errors (DKIM/DMARC)")
|
| 26 |
+
score += 5
|
| 27 |
|
| 28 |
+
# 2) From / Reply-To mismatch (domain-level)
|
| 29 |
+
from_addr = headers.get("From", "") or ""
|
| 30 |
+
reply_to = headers.get("Reply-To", "") or ""
|
| 31 |
+
from_domain = re.search(r'@([a-zA-Z0-9.-]+)', from_addr)
|
| 32 |
+
reply_domain = re.search(r'@([a-zA-Z0-9.-]+)', reply_to)
|
| 33 |
+
if from_domain and reply_domain:
|
| 34 |
+
if from_domain.group(1).lower() != reply_domain.group(1).lower():
|
| 35 |
+
findings.append(f"Header: Reply-To domain mismatch (From: {from_domain.group(1)}, Reply-To: {reply_domain.group(1)})")
|
| 36 |
+
score += 20
|
| 37 |
+
|
| 38 |
+
# 3) Suspicious sender domain
|
| 39 |
+
sender = headers.get("From", "") or ""
|
| 40 |
match = re.search(r'@([a-zA-Z0-9.-]+)', sender)
|
| 41 |
if match:
|
| 42 |
domain = match.group(1).lower()
|
| 43 |
+
parts = domain.split(".")
|
| 44 |
if any(free in domain for free in ["gmail.com", "yahoo.com", "outlook.com"]):
|
| 45 |
findings.append(f"Header: Free email provider used ({domain})")
|
| 46 |
score += 10
|
| 47 |
+
if len(parts) > 4 or (parts and any(char.isdigit() for char in parts[0])):
|
| 48 |
findings.append(f"Header: Suspicious-looking domain ({domain})")
|
| 49 |
score += 15
|
| 50 |
|
| 51 |
+
# 4) BCC usage (note: often stripped)
|
| 52 |
+
if headers.get("Bcc"):
|
| 53 |
findings.append("Header: Email sent with BCC (common in mass phishing)")
|
| 54 |
score += 15
|
| 55 |
|