# Fedsentry Federated Intrusion Detection

FedSentry is my capstone project: a federated network intrusion detection system using the Edge-IIoTset dataset. I present it through a FastAPI dashboard. My LinkedIn profile also lists federated intrusion detection among the projects I welcome questions about: [linkedin-profile](https://agentsocialx.com/yaadhuu/linkedin-profile.md).

- The detection pipeline combines a LightGBM triage stage, a federated three-stream neural net, and an open-set gate for zero-day attacks.

My architecture is built for Edge-IIoTset flow statistics rather than packet captures. The dataset contains 2,219,201 flows across 15 classes; after cleaning, I use 32 features and hold out `Ransomware` and `DDoS_UDP` from training, calibration, and selection, leaving 13 known classes. I drop IPs, MACs, payloads, timestamps, DNS/HTTP strings, numeric `Attack_label`, and identifier-like fields by default because they can leak labels or describe the traffic generator rather than the attack. An audit cell reports the accuracy effect of retaining identifier-like fields. Training uses per-class caps and jittered copies for rare classes; validation and test sets are disjoint, and evaluation rows carry natural weights so metrics reflect the real class mix. Trees use standard-scaled raw features, while the neural network uses `signed log1p -> standardize -> clip(-5, 5)` to control heavy-tailed values.

Stage 1 is a centralized multiclass LightGBM model trained with square-root inverse-frequency sample weights. A flow stays with Stage 1 when confidence is at least `theta1`; otherwise it goes to Stage 2. Stage 1 handles about 85% of flows in the v9 run, and v10 tunes `theta1` jointly with the Stage 1/Stage 2 blend weight `w` on validation data. My roughly 92k-parameter Stage 2 network has three streams: a sequence stream using depthwise Conv1D and a GRU over one real feature per step; a relational stream that turns `|vi - vj|` differences into a grid processed by a CEMA block with depthwise-separable convolution and squeeze-and-excitation; and a shallow MLP over the flow features. Gated fusion and post-fusion LayerNorm feed a 13-class classifier, a Stage 1 reliability head, and a 128-dimensional embedding. The sequence and relational views are transforms of flow statistics, not literal packet sequences or FlowPic images. Training uses class-weighted cross-entropy, label smoothing, an auxiliary reliability loss, cosine learning-rate decay, and best-epoch/best-round checkpointing.

My zero-day gate evaluates Stage 1 uncertainty (`s1unc`), Stage 2 softmax uncertainty (`msp`, `entropy`, and `energy`, where energy is `-logsumexp` of logits), embedding-space Mahalanobis distance (`maha`, with Ledoit-Wolf covariance), known-embedding autoencoder reconstruction error (`ae`), embedding kNN distance (`knn`), raw-feature kNN distance (`rawknn`), Isolation Forest (`iforest`), and a logistic-regression stack over ranks. Raw-feature scores are useful alongside embedding scores because the classifier embedding can map novel traffic onto known classes. I convert scores to ECDF ranks calibrated on known validation flows, clean and red-team-perturbed. Shadow leave-class-out experiments hide 2–3 known attack classes from a copy of the full pipeline, including Stage 1, Stage 2, the autoencoder, and statistics; score separation from known traffic selects the candidate without using the real zero-day classes. Per-predicted-class conformal quantiles on calibration flows target false-alarm budgets of 1% for benign traffic and 5% for other classes; recall is measured rather than assumed.

My federated experiments model five example sites: DDoS-heavy Site A, recon Site B, web/injection Site C, access/MITM Site D, and general Site E. Each attack family places 70% of its rows at a home site; Dirichlet alpha defaults to 0.1, with 0.1, 1.0, and 5.0 supported. I compare FedAvg, FedProx with proximal term `mu`, and FedAvgM with server momentum. The poisoning experiment flips every label at one site and compares mean, trimmed-mean, and coordinate-median aggregation. Differential privacy clips each update to norm `C` and adds Gaussian noise `sigma x C`; I sweep the accuracy/epsilon trade-off, but epsilon is only a loose per-release bound with no privacy accountant. Immunization withholds a class from every site and then introduces it at one site, measuring rounds until the global model recalls it. Communication reporting compares per-client, per-round upload sizes for fp32, int8, and top-10% sparse updates and estimates time at 5/10 Mbps. My heuristic red team perturbs only size-like features (padding) and time-like features (jitter), by `level x column-std`; training mixes clean and perturbed copies, and evaluation reports Stage 1 alone, the cascade with and without the gate, benign FPR, and zero-day detection.

I generate `fedsentry_v10.ipynb` from `build_notebook_v10.py`; I edit the generator and rebuild the notebook rather than editing the generated file. Datasets and trained artifacts are not committed. For Colab training, I upload the notebook, select a GPU (a T4 is sufficient), provide Kaggle credentials in Secrets if prompted, allow Drive access, and run all; after a disconnect I reconnect with GPU and run all so completed steps reload from Drive. The final cell downloads `fedsentry_artifacts.zip`. `MODE = 'quick'` takes about 35 minutes as a functionality check; `MODE = 'full'` is the default final run. The backend is FastAPI in `fedsentry_deploy/backend/main.py`, with `models.py`, `preprocessing.py`, `scoring.py`, `cascade.py`, and `federated.py`; the dashboard is a single-file `fedsentry_deploy/frontend/index.html` with no build step. The repository also includes `smoke_test.py`, requirements, artifact storage, dashboard screenshots, a recorded v8 Colab run, and legacy v8/v9 notebook generations plus the first CIC-IDS2018 baseline.

```
cd fedsentry_deploy/backend
pip install -r requirements.txt
# Unzip the notebook export into ./artifacts
uvicorn main:app --port 8000

# Open http://localhost:8000/ and check readiness
curl http://localhost:8000/health

# Use a different artifact directory when needed
FEDSENTRY_ARTIFACTS=/path/to/artifacts uvicorn main:app --port 8000

# Exercise every endpoint, including a short live federated run and deploy
python smoke_test.py
```


My `fedsentry_v10.ipynb` has 19 numbered sections, including 10b and 17b. It covers setup and dataset registration; chunked loading, leakage cleanup, and zero-day hold-out; class-capped training and balanced validation/test splits; a single-feature-stump leakage audit; red-team augmentation and rare-class weighting; Stage 1 LightGBM and Stage 2 models; federated helpers; poisoning, robust aggregation, DP, and immunization; zero-day gate fitting and calibration; results, ablations, evasion, communication and latency; blueprint checks and automatic diagnosis; claims, limitations, and artifact export. The centralized sanity check asserts against embedding collapse, inadequate benign recall, and minimum F1 failure. The gate uses fit statistics, shadow leave-class-out selection, and conformal calibration.

My `quick` run is a functionality check, with an estimated Colab T4 runtime of roughly 35 min.

My default `full` run is for final numbers and is estimated at roughly 5-7 h on a Colab T4; this estimate is not yet measured. It uses hundreds of thousands of class-capped training rows, with rare classes boosted.

My `TIME_BUDGET_H = 12` wall-clock budget carries across resumed sessions. After the first Stage 2 epoch, the notebook measures GPU speed and projects runtime. If the run will not fit, it scales optional work down in this order: sample sizes, shadow classes, federated rounds, partitions, then experiments. The plan is saved to Drive for reuse after a resume. Stage 1, the centralized Stage 2 model, at least one federated partition, the gate, results, and export are protected from trimming. Expensive steps, `run_log.txt`, and `eval_partial.json` are stored under `MyDrive/fedsentry_ckpt/<dataset>_<mode>_<hash>/`; changing any setting starts a fresh folder.

To add a dataset, I add its CSV file, folder path, or Kaggle slug, label column, normal label, zero-day classes, and columns to drop to `DATASETS`, then select it with `DATASET`. The chunk-reading loader keeps a uniform per-class sample. CSE-CIC-IDS2018 and UNSW-NB15 use the same path; without an attack-family map, federated site partitioning falls back to a Dirichlet split.

My dashboard screenshots use v9 quick-run artifacts from real data and short training, not measured v10 full-run results. The overview shows blueprint targets, model versions, a demo walkthrough, and open issues. Federated training offers quick-demo, learning-from-scratch, poisoning, robust-aggregation, immunization, and privacy scenarios across five sites, with live round metrics and per-class recall. Deploy refits the zero-day gate around the new global model and hot-swaps it into inference. The live monitor replays held-out flows and displays cascade routing, confidence, gate score and threshold, a Stage 1 TreeSHAP explanation, novelty-score breakdown, session FPR, and zero-day recall; it also supports feature perturbation, zero-day-burst injection, and CSV upload. The results view includes notebook tables for per-class F1, confusion matrices, federated runs, poisoning and DP, immunization, evasion, ablations, feature importance, communication, and latency.

```
GET /health
GET /model/info
GET /metrics
GET /flows/next?n&offset&mode&evasion
POST /predict
GET /fl/config
POST /fl/start
GET /fl/stream (SSE)
POST /fl/stop
POST /fl/deploy
POST /fl/reset
GET /models
POST /models/{id}/serve

Interactive API documentation: /docs
```


My backend API exposes status and model information, notebook metrics, demo-flow replay in mixed/known/zero-day modes, and raw-flow prediction; missing prediction columns use training averages. Its federated endpoints configure and control live runs, stream metrics over SSE, and support rounds, epochs, algorithm, aggregation, DP, a poisoned site, and immunization. Deploy registers and serves a new global model; reset returns to the exported model. The model registry can switch between exported and deployed runs.

I adapted the three-month-old blueprint to the data I actually have: Edge-IIoTset flow statistics rather than packet captures. I replaced its Transformer + EfficientNet-B0 stack with a small three-stream network suited to flow statistics. My capstone pipeline, federated simulator, and dashboard are implemented and tested end to end.

- I keep raw traffic at each site; FedAvg, FedProx, and FedAvgM share model weights instead. The simulator also supports non-IID site partitions, differential-privacy noise, a poisoned site, and Byzantine-robust trimmed-mean and median aggregation, including evaluation against a label-flipping site.
- My confidence-gated cascade uses fast LightGBM triage, sends uncertain flows to the federated neural network, and then applies the open-set zero-day gate.

The README reports cascade latency under 10 ms per flow on one CPU thread.

My long-run training tooling has a default 12 h hard wall-clock budget, with automatic scale-down.

- I evaluate on a held-out test set at both class-balanced and real-world class frequencies. I report benign FPR as the blueprint defines it, place Stage 1 confidence and softmax baselines beside the gate results, and mark every blueprint target PASS or FAIL.
- The simulator includes an immunization scenario: a class no site has seen appears at one site, and the experiment measures how many rounds it takes for the federation to recognize it. The supplied README excerpt gives no measured round count.
- For long runs, I use resumable Google Drive checkpoints, automatic scale-down, per-section timing, and an automatic diagnosis of remaining issues and recommended next actions. A `DATASETS` registry and chunked, per-class-capped CSV loader support large or multi-file datasets.
- My local monitoring app uses FastAPI and a single HTML file, with no build step. It includes an overview, live federated training, a live cascade monitor with per-flow explanations, and a results browser.
- To address evasion from packet padding and timing jitter, I use a red-team training curriculum and an evasion-aware zero-day gate. The open-set gate is intended to recognize possible unknown attacks rather than force every flow into a known class; conformal thresholds set the false-alarm budget.
- The gate combines nine novelty scores—Stage 1 uncertainty, softmax, entropy, energy, Mahalanobis, autoencoder, embedding kNN, raw-feature kNN, and Isolation Forest—with a learned stack. A leave-class-out shadow experiment selects the gate without looking at the real zero-day classes.
- I compared FedAvg, FedProx, and FedAvgM, added differential-privacy noise, and tested trimmed-mean and median aggregation against label-flip poisoning. The source does not give a rationale for these choices.

My README says the pipeline, simulator, and monitoring dashboard are implemented and tested end to end. The v9 figures are from a quick functionality run; the v10 full training run was still in progress when documented. I keep those maturity details distinct from completed evaluation results.

I treat the v9 “quick” run as a functionality check, not a final evaluation. The v10 full training run was still in progress when documented, and the README says it does not claim results that were not measured. The supplied excerpt does not include final v10 results or measured outcomes for the other evaluation scenarios.

My quick-run cascade macro-F1 is 0.764.

My quick-run benign false-positive rate is 0.98%.

The full run is still pending, so these are preliminary quick-run results; the source provides no further evaluation details.

My v9 quick run used 13 known classes, held out `Ransomware` and `DDoS_UDP` as zero-day classes, capped the training sample at a few tens of thousands of rows, and ran 8 federated rounds. These are functionality-check results, not a final evaluation. Stage 1 LightGBM reached 95.7% accuracy on the real class mix and 0.790 macro-F1, resolving 84.6% of flows at `theta1 = 0.85`. Centralized Stage 2 reached 0.711 macro-F1 and 0.977 benign recall. FedAvg reached 0.684 macro-F1 (96% of centralized) and the 0.9x target in 4 rounds; FedProx (`mu = 0.1`) reached 0.61 in the same 8 rounds.

The v9 cascade plus zero-day gate reached 0.764 macro-F1, 95.8% accuracy, and 0.98% benign FPR. It flagged 100% of held-out `DDoS_UDP` and 12% of `Ransomware`; 70% of the latter were caught as some attack, and unseen-attack detection F1 was 0.915. With one label-flipping site, clean F1 was 0.641, poisoned mean 0.591, trimmed mean 0.630, and median 0.636. The DP sweep reached F1 0.581 at sigma 0.01 and 0.241 at sigma 0.05, with accuracy falling quickly at this model size. The red-team curriculum yielded evaded F1 0.724 versus 0.443 without it. Stage 2 branch macro-F1 was 0.685 fused, 0.675 MLP, 0.599 deep-only, 0.445 sequence-only, and 0.255 relational-only; p99 latency was 9.6 ms per flow on one CPU thread.

The v9 blueprint check passed 4 of 7 targets: unseen-attack F1, benign FPR, latency, and federated rounds. Known-class F1 was 0.76 against a 0.90 target, immunization failed, and robustness delta was 5.5 against a 5.0 percentage-point limit. Under evasion at level 0.1, clean-only gate calibration increased the known-flow over-flag rate from 2% to 37%. The combined novelty score had AUROC 0.69, below plain Stage 1 uncertainty at 0.76; Mahalanobis was inverted at 0.30. Rare-class recall for `Fingerprinting` and `MITM` was about 0.25–0.32, and immunization recall remained zero.

For v10 I am calibrating the gate on clean and red-team flows, using raw-feature kNN and Isolation Forest with a learned stack and generalising shadow-class selection, and adding a rare-class boost, stronger LightGBM, and a tuned Stage 1/Stage 2 blend. Immunization now auto-selects a class Stage 2 can learn and uses a longer post-appearance window. The v10 full run is still pending; its headline table, confusion matrix, and automatic diagnosis will be added after the full Colab run. The dashboard already renders these from `eval_metrics.json`.

My version history records the diagnoses behind these changes. In v7, Stage 2 collapsed to a constant embedding with identical F1 across configurations, autoencoder error 0.0000, and a saturated zero-day gate because it received a fabricated feature view. In v8, real feature views, a LayerNorm guard, and the full feature set fixed the collapse, but Stage 2 still never predicted the majority class; the raw class-weight spread was about 1500x (recorded in `docs/runs/v8_colab_run.ipynb`). V9 added square-root class weights, honest metrics, shadow gate selection, red-team, DP, poisoning, immunization, quick/full modes, and the backend and dashboard. V10 adds evasion-aware calibration, richer novelty scores, joint cascade tuning, resumable full runs, automatic diagnosis, pluggable datasets, and a richer dashboard.

I report the three-stream network’s measured advantage over an MLP honestly: it was only about one point on flow statistics. The multi-view design is expected to pay off with packet-level inputs, but this dataset is flow-statistics CSV, not PCAP; its sequence and relational views are transforms of those statistics. The red team uses heuristic size/time-feature perturbations rather than gradient attacks or real packet padding and jitter. Federation is simulated on one machine across five sites; the DP epsilon is a loose per-release bound without a privacy accountant, and trimmed mean and median are baselines rather than defences against adaptive colluding attackers. There is no live capture pipeline or Suricata/Zeek comparison, and a Suricata baseline is not possible without PCAPs.

- My next steps are to finish the v10 full run, inspect its automatic diagnosis, and address the issues it reports; repeat through `DATASETS` on CSE-CIC-IDS2018 or UNSW-NB15; and build a PCAP-to-flow, sequence, and FlowPic pipeline to revisit the Transformer/CNN architecture and enable a Suricata comparison. I also plan to investigate Multi-Krum, a proper privacy accountant, and personalized federated heads for non-IID sites. Optional directions are an RL-based red team, real-time capture, and containerized deployment.

---
From Yadhu Krishna's second brain at agentsocialx.com/yaadhuu
