#WRAP #Cybersecurity #Phishing #AI #SOC #ThreatHunting #Python
Why I Started This Project
Working in a SOC, phishing emails are something I have dealt with quite often.
The investigation itself is usually not complicated. But there are many small things an analyst needs to check before deciding whether an email is actually malicious.
You start with the email and then check the headers.
Then the URLs.
Then the domains and IP addresses.
Then SPF, DKIM and DMARC.
Then you start checking threat intelligence.
If there is an attachment, you investigate that as well.
After all of that, you still need to document your findings and explain why you believe the email is malicious or legitimate.
When you do this for one email, it is manageable.
When you have to do it repeatedly, it becomes time-consuming.
That was the reason I started thinking:
What if I could automate the repetitive part of the investigation and leave the analyst to focus on the actual decision?
That idea eventually became PhishGuard AI.
⸻
What I Wanted to Build
My initial idea was quite simple.
I wanted to give the system an .eml file and have it automatically perform the first level of phishing analysis.
Something like:
.EML File
↓
Parse Email
↓
Extract Indicators
↓
Analyze Headers
↓
Check SPF/DKIM/DMARC
↓
Threat Intelligence
↓
Correlate Results
↓
Calculate Risk
↓
Generate SOC Report
The interesting part for me was not just adding AI.
There are already many tools that use AI.
The question I wanted to answer was:
Where does AI actually make sense in a SOC phishing investigation?
⸻
My First Mistake: Giving the LLM Too Much Responsibility
One of the first things I experimented with was using an LLM to analyze the email and directly give me a verdict.
The idea looked attractive:
Email
↓
LLM
↓
Phishing / Legitimate
But while working on it, I realized there was a problem.
An LLM can produce a very convincing explanation even when the underlying evidence is weak.
For example, imagine the model sees:
SPF: FAIL
It might conclude that the email is malicious.
But SPF failure by itself doesn’t prove that.
The same applies to a newly registered domain, a suspicious-looking URL, or an unusual IP address.
These are signals, not absolute proof.
That made me change the architecture.
⸻
The Architecture I Finally Settled On
Instead of asking AI to do everything, I separated the responsibilities.
The basic architecture became:
Email
↓
Python
↓
Evidence
↓
Risk Scoring
↓
LLM
↓
SOC Report
In other words:
Python is responsible for the investigation. AI is responsible for explaining the investigation.
That became the most important design decision in the project.
⸻
What I Used to Build It
The project is mainly built around Python and a few supporting technologies.
Core
Python
I use Python for most of the actual processing:
- EML parsing
- Header extraction
- IOC extraction
- Enrichment
- Correlation
- Caching
- Risk scoring
AI
I used:
One of the reasons I chose Ollama was that I wanted to experiment with running the LLM locally rather than sending the complete email content to a cloud AI service.
For cybersecurity data, I think this is an important consideration.
RAG
I also experimented with:
This allows relevant knowledge to be retrieved and provided to the model when generating the final report.
Threat Intelligence
For enrichment, I worked with sources such as:
- VirusTotal
- AbuseIPDB
- WHOIS
- MXToolbox
⸻
Step 1: Give It an EML File
The workflow starts with a single .eml file.
The system parses the message and extracts information such as:
From
To
Subject
Date
Reply-To
Return-Path
Message-ID
Received headers
URLs
Domains
IP addresses
Attachments
Authentication results
I wanted this to happen automatically because manually copying indicators from every email is exactly the kind of repetitive task I wanted to eliminate.
⸻
Step 2: Look at the Headers
The email body is only one part of the investigation.
The headers can tell a completely different story.
For example, imagine seeing:
From: security@company-example.com
Reply-To: something@external-domain.com
That immediately deserves investigation.
But I don’t want the system to say:
“Reply-To is different, therefore phishing.”
Instead, it treats the mismatch as one piece of evidence.
This distinction is important because security investigations are rarely based on one indicator.
⸻
Step 3: SPF, DKIM and DMARC
The next part is email authentication.
The system checks:
SPF
Was the sending server authorized to send email for the domain?
DKIM
Does the email’s cryptographic signature validate?
DMARC
Does the message align with the domain’s authentication policy?
These checks are useful, but I learned not to treat them as a simple pass/fail phishing detector.
For example:
SPF = PASS
DKIM = PASS
DMARC = PASS
doesn’t automatically mean the email is safe.
A legitimate account could potentially be compromised.
Likewise:
SPF = FAIL
doesn’t automatically mean the email is malicious.
The context matters.
⸻
Step 4: Extract the IOCs
This is one of the parts where automation really starts saving time.
The system extracts indicators from the email, including:
URLs
Domains
IP addresses
File hashes
Email addresses
Attachment names
For example:
https://secure-login-example.com/verify
can be broken down into:
URL:
https://secure-login-example.com/verify
Domain:
secure-login-example.com
Once these indicators are extracted, I can send them through the enrichment pipeline.
⸻
Step 5: Threat Intelligence Enrichment
Now the interesting part begins.
The extracted indicators can be checked against threat-intelligence sources.
For example, VirusTotal can provide reputation information for domains, URLs, IPs, and hashes.
AbuseIPDB can provide reputation information about IP addresses.
WHOIS can provide additional information about domains.
Instead of simply storing:
Malicious
I wanted the system to retain the actual evidence.
Something like:
Indicator: suspicious-domain.example
Type: Domain
Reputation: Suspicious
Detection information: …
That evidence can then be used by the scoring engine.
⸻
One Thing I Added: IOC Caching
While working on the project, I noticed another practical problem.
The same indicators appear again and again.
Imagine 50 phishing emails containing the same malicious domain.
I don’t want to make 50 identical API requests.
So I added IOC caching.
The basic idea is:
Indicator
↓
Is it already cached?
↓
┌───────────────┐
│ │
Yes No
│ │
↓ ↓
Use result Query API
↓
Save result
This makes repeated investigations faster and also helps reduce unnecessary API calls.
It became especially useful when I started testing the pipeline against larger collections of phishing emails.
⸻
The Most Important Part: Risk Scoring
I didn’t want a single indicator to decide whether an email was phishing.
For example:
DMARC failed = Phishing
would be far too simplistic.
Instead, I wanted to combine multiple signals.
A simplified example could be:
Suspicious domain +20
Malicious URL +40
Suspicious IP +30
Authentication anomaly +15
Suspicious attachment +25
New domain +15
Known malicious hash +50
The actual values can be changed depending on the environment.
The important idea is:
One suspicious indicator may not mean much. Several independent indicators together can tell a very different story.
The final result can then be classified as:
LOW
SUSPICIOUS
HIGH
This also makes the decision easier to explain.
⸻
Where Mistral Comes In
Once Python has finished collecting the evidence, I send the structured findings to the local LLM.
This is where Mistral becomes useful.
Instead of asking:
“Is this email phishing?”
I can give it something like:
Email information
+
Authentication results
+
Extracted IOCs
+
Threat intelligence
+
Risk score
+
Investigation findings
and ask it to turn those findings into a readable SOC report.
That is a much better use of an LLM in my opinion.
The model doesn’t need to invent the investigation.
It just needs to explain what the investigation already found.
⸻
A Simple Example
Imagine I receive an email saying:
Your Microsoft 365 account will be suspended.
Click here to verify your account.
The analyst might initially think it looks like a normal Microsoft notification.
But the pipeline starts checking it.
It finds:
From:
Microsoft-looking sender
Reply-To:
Unrelated external domain
URL:
Credential harvesting page
Domain:
Does not belong to Microsoft
Threat Intelligence:
Suspicious
Authentication:
Additional anomalies
Now the system has several pieces of evidence.
Instead of simply saying:
“This is phishing.”
the report can explain why it has been classified as high risk.
For example:
Verdict: HIGH RISK
Key Findings:
- The reply-to address does not match the expected sender.
- The embedded URL points to an unrelated domain.
- The destination domain has suspicious reputation information.
- The email contains characteristics consistent with credential harvesting.
Recommended Actions:
- Quarantine the email.
- Block the identified indicators.
- Search for the same indicators across the mail environment.
- Identify users who interacted with the URL.
- Investigate related authentication activity.
That is the type of output I wanted from the project.
⸻
I Also Experimented With RAG
Another part of the project was experimenting with RAG using Chroma.
The idea was to provide the model with relevant security knowledge alongside the investigation evidence.
Conceptually:
Investigation Evidence
+
Relevant Knowledge
↓
RAG
↓
Mistral
↓
SOC Report
The purpose isn’t to let the AI freely make security decisions.
Instead, it gives the model better context when explaining the findings.
⸻
What Happened When I Tested More Emails?
Testing individual emails is easy.
Testing a larger dataset is where things become interesting.
Once you start processing many emails, you encounter problems that aren’t obvious when testing a single sample.
For example:
- Some emails are malformed.
- Some don’t contain all expected headers.
- Some indicators cannot be enriched.
- The same IOC appears repeatedly.
- APIs have rate limits.
- Some emails contain very long content.
- Different email structures require different parsing logic.
This is where I realized that building a cybersecurity automation project isn’t only about the main detection logic.
The small engineering details matter too.
⸻
The Biggest Lesson I Learned
The biggest lesson from this project was actually about where not to use AI.
It is tempting to build something like:
Email → AI → Verdict
because it looks impressive.
But in a security environment, I would rather have:
Email
↓
Evidence
↓
Deterministic Logic
↓
Risk Score
↓
AI Explanation
Why?
Because if an analyst asks:
“Why did you classify this as high risk?”
I can trace the answer back to actual evidence.
I can show:
- Which URL was extracted.
- Which domain was found.
- What the authentication results were.
- What the threat-intelligence sources returned.
- Which scoring conditions were triggered.
That makes the system much easier to trust.
⸻
What I Would Like to Add Next
PhishGuard AI is still something I consider a work in progress.
There are several things I would like to add.
Attachment Analysis
I want to improve how suspicious attachments are analyzed and eventually integrate isolated sandbox analysis.
SIEM Integration
The system could send the final verdict and indicators to:
- Microsoft Sentinel
- Splunk
- IBM QRadar
That would make the project more useful in an actual SOC workflow.
SOAR Integration
A future workflow could look like:
Phishing Detected
↓
Enrich IOCs
↓
Calculate Risk
↓
Create Incident
↓
Search Mailboxes
↓
Block IOC
↓
Notify Analyst
Of course, automated blocking should only happen for sufficiently high-confidence cases and with appropriate safeguards.
Analyst Feedback
I would also like to allow analysts to mark the final result as:
True Positive
False Positive
Benign
That feedback could eventually be used to improve the detection logic.
⸻
What I Learned From Building It
There are a few things I would take away from this project.
- AI is not a replacement for security logic
The model is powerful, but it shouldn’t be responsible for everything.
- Evidence matters more than an AI confidence score
I would rather know why something is suspicious than receive:
Phishing probability: 97%
without any supporting evidence.
- Context is extremely important
A failed SPF check by itself isn’t enough.
A suspicious domain by itself isn’t always enough.
A malicious IP reputation result is useful, but context still matters.
When several independent signals point in the same direction, the confidence becomes much stronger.
- Automation should reduce repetitive work
The goal isn’t to replace the analyst.
The goal is to let the analyst spend less time copying indicators between tools and more time investigating what actually happened.
⸻
Final Thoughts
I started PhishGuard AI with a simple question:
Can I automate the repetitive parts of phishing investigation without blindly trusting an AI model?
The answer I arrived at was yes—but only if the responsibilities are separated properly.
Python handles the investigation.
Threat intelligence provides additional context.
Risk scoring combines the evidence.
The LLM turns the results into something an analyst can quickly understand.
And the analyst remains responsible for the final decision.
For me, that is where AI becomes genuinely useful in cybersecurity.
Not:
“AI will replace the SOC analyst.”
But:
“AI can help the SOC analyst spend more time on the investigation and less time on repetitive work.”
That is the idea behind PhishGuard AI.
Evidence first. Automation second. AI where it actually adds value.
⸻
Technology Stack
Python
↓
EML Parsing & IOC Extraction
↓
VirusTotal / AbuseIPDB / WHOIS
↓
Correlation & Risk Scoring
↓
Chroma RAG
↓
Ollama + Mistral
↓
SOC-Style Phishing Report
#WRAP #Cybersecurity #Phishing #AI #Python #SOC #ThreatHunting #ThreatIntelligence #SecurityAutomation #BlueTeam