Skip to content
aimenbensadia1Public

About

Mini SOC pipeline: rule-based, Isolation Forest, and Random Forest detectors on CICIDS2017, with LLM-powered alert analysis and a Streamlit dashboard

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

MiniSOC

Author: Aimen Bensadia · Email: aimenbensadia118@gmail.com · Date: 2026-05-25

A mini Security Operations Center pipeline — from raw network data to a trained anomaly detector and an LLM-powered alert analyst — built on the CICIDS2017 benchmark dataset.


Table of Contents

  1. What We Built
  2. Dataset — CICIDS2017
  3. Step 1 — Exploration
  4. Step 2 — Cleaning
  5. Step 3 — Rule-Based Detector
  6. Step 4 — Isolation Forest
  7. Step 5 — Random Forest
  8. Step 6 — LLM Analyst
  9. Step 7 — Interactive Dashboard
  10. Final Comparison
  11. Quick Start
  12. Project Structure

What We Built

A full detection pipeline starting from a raw network traffic CSV, ending with three detectors compared head-to-head, an LLM that explains each alert in plain English, and an interactive dashboard to explore them.

Raw CSV  →  Clean  →  Rule-Based  →  Isolation Forest  →  Random Forest
                           ↓                ↓                    ↓
                       79.8% F1        28.8% F1              99.9% F1
                                            ↓
                                   LLM Analyst (llama3.2)
                                            ↓
                              Interactive Dashboard (Streamlit)

Dataset — CICIDS2017

The Canadian Institute for Cybersecurity IDS 2017 dataset is a standard benchmark for network intrusion detection. Each row is a network flow — a full conversation between two hosts, summarised as 78 statistical features.

We used the Friday afternoon DDoS file: Friday-WorkingHours-Afternoon-DDos.pcap_ISCX.csv

Label Distribution

Property Value
Total rows 225,745
Features 78 numeric + 1 label
BENIGN flows 97,718 (43.3%)
DDoS flows 128,027 (56.7%)

The 78 Features — 5 Buckets

Bucket Columns What they measure
Directional Fwd *, Bwd * Traffic from client→server (Fwd) and server→client (Bwd)
Volume & Size Total * Packets, * Length Mean/Std/Max/Min How much data and how large the pieces
Time & Speed Flow Duration, * IAT *, Flow Bytes/s, Flow Packets/s How fast, how long, gaps between packets
TCP Flags SYN/ACK/FIN/RST Flag Count Connection handshake signals
Active / Idle Active *, Idle * Periods of activity vs silence within a flow

Step 1 — Exploration

Script: explore_cicids2017.py

We compared mean feature values between BENIGN and DDoS flows and found a clear fingerprint:

Feature BENIGN DDoS Signal
Fwd Packet Length Mean 371 bytes 7 bytes Attackers spam tiny packets
Bwd Packet Length Mean 117 bytes 1,481 bytes Server sends large error responses
Total Backward Packets 6.3 3.3 Server starts dropping connections

The chart below shows why Fwd Packet Length Mean is the smoking gun — the two distributions barely overlap:

Fwd Packet Length Distribution

DDoS flows cluster hard at 0–10 bytes (tiny flooding packets). Normal traffic spreads across a wide range of meaningful payload sizes. The yellow dashed line is the 20-byte threshold used in the rule-based detector.


Step 2 — Cleaning

Script: clean.py → produces data/friday_clean.csv

Issue Cause Action Rows affected
Negative Flow Duration Corrupt packet captures Dropped 2
inf in Flow Bytes/s / Flow Packets/s Division by zero (0-duration flows) Replaced with NaN → dropped 34
NaN in key columns Upstream data gaps Dropped 0
Total removed 36 rows
Rows kept 225,709 (99.98%)

Step 3 — Rule-Based Detector

Script: detect.py

A purely statistical baseline — no ML, pure pandas. Learns what "normal" looks like from BENIGN flows, then flags anything outside those bounds. Analogous to: "flag any login from a country this user has never logged in from before."

Three Rules

Rule Threshold How it's set Signal
R1 Fwd Packet Length Mean < 20 bytes 20 b (domain knowledge) Minimum meaningful TCP payload Tiny-packet flood
R2 Flow Packets/s > 666,667 99th pct of BENIGN Learned from normal traffic Volumetric rate attack
R3 Bwd Packet Length Mean > 1,507 bytes 99th pct of BENIGN Learned from normal traffic Server under stress

An alert fires when any rule triggers.

Results (full dataset)

Metric Value
Total alerts 160,293 (71% of flows)
False positives 32,268
Precision 79.9%
Recall 100.0%

R1 does 99% of the work. The 32k false positives are legitimate ACK-only and DNS flows that also have tiny forward packet sizes — the rules can't distinguish them from flood traffic.


Step 4 — Isolation Forest

Script: iforest.py

Trains an IsolationForest on BENIGN flows only — the model has never seen attack labels. It learns to score how "abnormal" each flow is by randomly isolating points in feature space. Anomalies (points that are easy to isolate) get flagged.

iforest = IsolationForest(n_estimators=100, contamination=0.05, random_state=42)
iforest.fit(X_benign)            # learns "normal" — never sees any labels
alerts = iforest.predict(X_all) == -1

Why It Struggled Here

DDoS in CICIDS2017 is a mass, homogeneous attack — 128k flows all look nearly identical. Isolation Forest relies on anomalies being rare and isolated. When an attack forms its own dense cluster, the forest treats it as a second normal region and fails to flag it.

Metric Value
Total alerts 28,912
False positives 4,885
Precision 83.1%
Recall 18.8%

Fewer false alarms than the rules, but misses 81% of the attacks. Isolation Forest is better suited for subtle, low-volume anomalies.


Step 5 — Random Forest

Script: rforest.py

A supervised classifier trained on labeled data (80/20 stratified split). It builds 100 decision trees, each voting on whether a flow is an attack.

rf = RandomForestClassifier(n_estimators=100, random_state=42, n_jobs=-1)
rf.fit(X_train, y_train)         # sees both BENIGN and DDoS labels

Feature Importance

The model independently discovered the same signals we found in EDA:

Feature Importance

Rank Feature Importance Why
1 Total Fwd Packets 28.1% DDoS sends many rapid bursts
2 Fwd Packet Length Mean 26.4% The 7-byte smoking gun
3 Bwd Packet Length Mean 19.4% Server stress indicator
4 Total Backward Packets 11.1% Server drop rate

The top 4 features account for 85% of the model's decisions — consistent with what we found manually in Step 1.


Step 6 — LLM Analyst

Scripts: analyze.py, make_report.py

For each flagged alert, the raw flow features are sent to a local LLM (llama3.2 via Ollama) with a SOC analyst prompt:

"You are a SOC analyst. Given these network flow logs, give a 3-sentence summary: What happened? Why is it suspicious? What should I check next?"

Results are saved to data/alert_summaries.jsonl. A readable markdown report can be generated with make_report.py.

python analyze.py              # analyses 20 sampled alerts (default)
python analyze.py --n 50       # analyse more
python analyze.py --provider groq  # use Groq free-tier API instead
python make_report.py          # writes data/alert_report.md

Example Output

Alert — DDoS — R1 + R3 triggered

A network flow was detected with extremely small forward packets (8.7 bytes mean) and unusually large backward packets (2,321 bytes mean), consistent with a DDoS tiny-packet flood. This is suspicious because the asymmetry — tiny requests triggering massive responses — is a classic amplification signature that saturates upstream bandwidth. I would check the source IP against threat intelligence feeds and inspect firewall logs for correlated connection attempts.


Step 7 — Interactive Dashboard

Script: dashboard.py

A Streamlit app that brings everything together: alerts ranked by anomaly score, ground-truth labels, triggered rules, and LLM summaries — all in one place. Alerts without summaries can be analysed on demand with a single click.

streamlit run dashboard.py
# Opens at http://localhost:8501

Features:

  • Alerts ranked by Isolation Forest anomaly score (most suspicious first)
  • Filter by rule and ground-truth label
  • Click any row to see the full feature table and LLM analysis
  • "Generate" button calls llama3.2 on demand and saves the result

Requires Ollama running locally (ollama serve) with llama3.2 pulled.


Final Comparison

All three models evaluated on the same held-out 20% test set (45,142 flows).

Model Comparison

Confusion Matrices

Numbers

Metric Rule-Based Isolation Forest Random Forest
Total alerts 32,101 5,446 25,602
True positives 25,605 4,476 25,590
False positives 6,496 970 12
Missed attacks 0 21,129 15
Precision 79.8% 82.2% 100.0%
Recall 100.0% 17.5% 99.9%
F1 88.7% 28.8% 99.9%

Takeaways

Rule-Based — perfect recall, but 6,496 false alarms. Great as a first-pass filter or when you have no labels. Fragile: a new attack type it wasn't tuned for would be completely missed.

Isolation Forest — fewest false alarms, but only catches 1 in 5 attacks. Works best for subtle, low-volume anomalies. Fails against dense, uniform floods.

Random Forest — wins on every metric simultaneously. Near-perfect precision and recall. The cost: it requires labeled training data. In a real SOC, you'd seed it with known attack signatures and retrain as new threats emerge.

The right architecture is all three in a pipeline:

  • Isolation Forest for unknown/novel anomalies
  • Rules for high-confidence known patterns
  • Random Forest as the final classifier when you have labels
  • LLM analyst for human-readable triage on every alert

Quick Start

Prerequisites

pip install pandas numpy scikit-learn matplotlib streamlit

For the LLM analyst, install Ollama and pull a model:

ollama pull llama3.2

Run the full pipeline

python explore_cicids2017.py   # optional EDA
python clean.py                # data/friday_clean.csv
python detect.py               # rule-based baseline
python iforest.py              # isolation forest
python rforest.py              # random forest + comparison
python visualize.py            # plots/
python analyze.py              # LLM summaries
python make_report.py          # data/alert_report.md
streamlit run dashboard.py     # http://localhost:8501

The raw CSV (Friday-WorkingHours-Afternoon-DDos.pcap_ISCX.csv) is not committed. Download it via Kaggle:

# place ~/.kaggle/kaggle.json first (from Kaggle account settings)
python explore_cicids2017.py   # auto-downloads on first run

Project Structure

MiniSOC/
├── explore_cicids2017.py   # download + load + explore the dataset
├── clean.py                # remove infinities, nulls, corrupt rows
├── detect.py               # rule-based anomaly detector (pure pandas)
├── iforest.py              # isolation forest vs rule-based comparison
├── rforest.py              # random forest + full three-way comparison
├── visualize.py            # generate all plots
├── analyze.py              # LLM analyst — per-alert SOC summaries
├── make_report.py          # convert JSONL summaries to markdown report
├── dashboard.py            # Streamlit alert dashboard
├── data/
│   ├── friday_clean.csv                 (generated by clean.py)
│   ├── alert_summaries.jsonl            (generated by analyze.py)
│   └── alert_report.md                  (generated by make_report.py)
└── plots/
    ├── 1_label_distribution.png
    ├── 2_fwd_packet_distribution.png
    ├── 3_model_comparison.png
    ├── 4_feature_importance.png
    └── 5_confusion_matrices.png

About

Mini SOC pipeline: rule-based, Isolation Forest, and Random Forest detectors on CICIDS2017, with LLM-powered alert analysis and a Streamlit dashboard

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages