NIDS
Attack-type hint, severity by vote count, per-model scores vs thresholds and key features (count, serror_rate, rerror_rate, src_unique_dst_ports …).
What is under the hood, which public datasets are supported (and which are benchmark-only), how decisions are explained, and which safeguards stand between a detection and an action.
All models share the same preprocessing: signed log1p transform followed by StandardScaler (compresses long-tailed bytes and counts).
| Model | Training | Score | Threshold | Strength / weakness |
|---|---|---|---|---|
| Isolation Forest | Unsupervised — normal data only | −score_samples | 99th percentile of normal scores | No labels needed, fast / may miss dense attacks such as SYN flood |
| Random Forest | Supervised — normal + attack | Attack probability | 0.5 | High accuracy, feature importance / weak on attacks not seen in training |
| LightGBM | Supervised | Attack probability | 0.5 | Fast on large data / label-dependent |
| Autoencoder (PyTorch) | Unsupervised — normal only | Reconstruction MSE | 99th percentile of normal error | Captures non-linear anomalies / sensitive to distribution shift (false alarms possible) |
Other models: HIDS = Isolation Forest (26 features); static malware = XGBoost (55 PE features) with SHAP; behavior = Random Forest (39 features from sandbox reports). Models are saved as joblib bundles (detector + preprocessor + thresholds + feature list + metrics).
common (NSL-KDD-compatible) 33; extended 53 in totalPayload-content features (e.g. hot, num_failed_logins) are intentionally excluded; only flow statistics are stored.
Feature systems differ per dataset, so models usable for live / pcap detection are kept apart from offline-benchmark models.
| Dataset | Use | Feature system | Live / pcap detection |
|---|---|---|---|
| NSL-KDD (UNB CIC) | NIDS training & benchmark. 125,973 train / 22,544 test (KDDTest+) records | common 33 (converted) | Yes |
| UNSW-NB15 (UNSW Canberra) | Offline benchmark. 175,341 train / 82,332 test records | native (original numeric columns) | No — feature mismatch; blocked at load |
| CIC-IDS2017 (UNB CIC) | Offline benchmark. 8 daily CSVs, about 2.8 M flows | native (CICFlowMeter columns) | No — use CICFlowMeter as capture engine for near-real-time scoring |
| EMBER 2017/2018 (Elastic) | Static malware training from raw feature JSONL (no binaries) | 55 PE features (converted; missing values = NaN) | Used by the scanner |
| SOREL-20M (Sophos / ReversingLabs) | Large-scale static training: ~20 M PEs as EMBER v2 features; export LMDB → JSONL, labels from meta.db | EMBER v2 raw JSON | Used by the scanner. Use features only — the binaries are real malware |
| Synthetic & your own baseline | Pipeline validation; unsupervised baseline from your normal pcap / logs | extended 53 / common 33 | Yes |
Synthetic data only validates the pipeline: high scores (even 100 %) reflect simple patterns, not real-world performance. Always retrain a baseline on your own normal traffic and measure the false-positive rate before operating.
Attack-type hint, severity by vote count, per-model scores vs thresholds and key features (count, serror_rate, rerror_rate, src_unique_dst_ports …).
Score vs threshold and the top 3 standardized features, e.g. ip_fail_window + ip_unique_users_window → brute force.
SHAP contributions in log-odds: positive pushes toward malicious, negative toward benign. Plus the matched YARA rules and reasons.
Each block lists the risk score and evidence (e.g. distinct_ports 20 in 10 s, failures 5 in 60 s) in list-blocks, the audit log and reports.
| Setting | Default | Meaning |
|---|---|---|
malware.verdict weights | static_ml 0.9 · yara 1.0 · virustotal 1.0 · dynamic 0.9 | Overall = max(signal × weight); ≥ 0.8 malicious, ≥ 0.5 suspicious |
policy.alert_threshold / block_threshold | 30 / 70 | Accumulated risk score for alert / block |
policy.half_life_seconds | 600 | Risk score half-life (decay) |
policy.ttl_seconds / ttl_escalation / ttl_max_seconds | 3600 / 2.0 / 86400 | First block TTL, multiplier on repeat offences, cap |
detectors.packet.scan_ports | 20 in 10 s | Distinct (dst, port) pairs ⇒ port scan |
detectors.packet.syn_threshold / udp_threshold | 200 / 500 in 5 s | SYN / UDP packets from one source ⇒ flood |
detectors.authlog.fail_threshold | 5 in 60 s | Auth failures from one IP ⇒ SSH brute force |
policy.quarantine_suspicious | false | Also quarantine “suspicious” files (off: false-positive risk) |
| Safeguard | Behavior |
|---|---|
| Default dry-run | With no options it only records what it would do; the system is unchanged |
| Double gate | --enforce and enforcement.allow: true are both required; either one alone stays dry-run |
| Allowlist | Private ranges, own address, gateway, DNS, current SSH clients and custom CIDRs are never blocked |
| TTL (auto release) | Blocks expire after 1 h by default; repeat offenders get ×2 up to 24 h |
| Concurrent block cap | max_blocks (default 200); beyond it, actions are only recorded |
| Dedicated table / chain | Rules go only into aisec_defense; rollback deletes only that — other rules untouched |
| Rollback | defend rollback or --rollback-on-exit reverts every action |
| Hash-chained audit log | Each record includes the SHA-256 of the previous one; verify-audit detects tampering |
| Destructive actions off | Process kill and account lock need config + --enforce; files are never deleted, only quarantined |
| Quarantine ≠ delete | Moved with permission 000, original hash and path kept; restore requires --yes |
Recommended order: observe in dry-run for several days → clean up the allowlist (add your admin IPs) → only then enable enforcement; keep console access (IPMI / cloud console) when testing remotely.
Every action — executed or dry-run — is appended to audit.jsonl with prev_hash and hash. The chain continues across rotated files and verify-audit reads them all. It detects edits; it cannot stop an attacker who rewrites the entire file, so keep remote or WORM copies.
$ python main.py defend verify-audit
OK audit.jsonl records=4 OK
# audit.jsonl 2번째 줄을 일부러 수정한 사본에서 (on a deliberately edited copy, line 2 modified):
FAIL audit.jsonl records=1 2번째 줄 해시 불일치(내용 변조 의심) [exit code: 1]$ python main.py defend self-test
[PASS] 집행 이중 게이트: --enforce 만으로는 dry-run (mode=dry-run)
[PASS] 공격자 3명 탐지·(가상)차단 (blocked=['203.0.113.50', '203.0.113.60', '203.0.113.77'])
[PASS] dry-run: 파일이 이동되지 않음
[PASS] dry-run: 방화벽 백엔드 없음 (backend=None)
[PASS] 감사 로그 해시 체인 정상 (records=4 OK)
[PASS] 정상 트래픽 오탐 없음 (events=0)
[PASS] 허용 목록(루프백)은 차단되지 않음 (blocks=0)
[PASS] 롤백: 모든 차단 해제 + teardown (calls=13)
… (16 checks in total / 총 16개 항목)
결과: 16/16 통과The enforce checks use a built-in fake firewall; real nft/iptables were verified separately in an isolated network namespace.
| Threat | Countermeasure |
|---|---|
| Exposure | Binds to 127.0.0.1 by default; non-loopback needs a token. Remote viewing via SSH tunnel is recommended (the UI does not serve HTTPS) |
| Token guessing / timing | Constant-time comparison; HttpOnly + SameSite=Strict cookie |
| DNS rebinding | Host header allowlist, otherwise HTTP 400 |
| CSRF | POST needs matching Origin, JSON content type and X-CSRF-Token |
| XSS | textContent only, nonce-based CSP, log values displayed as text |
| Path traversal | Reports and static files by name allowlist / basename only |
| Unintended changes | Release/restore need --allow-actions; releasing firewall-enforced entries also needs --enforce + enforcement.allow; restore needs confirm=true |
| Accountability | Every request is logged to ui/access.jsonl (no query string or token) |
Table 9 of the manual. “Synthetic” = generated traffic from the same generator that produced the training data. NSL-KDD = official KDDTest+, which contains attack types absent from the training set (e.g. mscan, apache2, snmpguess).
| Dataset | Model | Accuracy | Precision | Recall | F1 | ROC-AUC | FPR |
|---|---|---|---|---|---|---|---|
| Synthetic (30 % hold-out) | Isolation Forest | 91.4% | 96.6% | 74.0% | 0.838 | 0.985 | 1.1% |
| Synthetic (30 % hold-out) | Random Forest | 100.0% | 100.0% | 100.0% | 1.000 | 1.000 | 0.0% |
| Synthetic (30 % hold-out) | LightGBM | 100.0% | 100.0% | 100.0% | 1.000 | 1.000 | 0.0% |
| Synthetic (30 % hold-out) | Autoencoder | 96.4% | 97.8% | 90.1% | 0.938 | 0.998 | 0.9% |
| NSL-KDD (KDDTest+) | Isolation Forest | 76.4% | 97.7% | 59.9% | 0.743 | 0.932 | 1.9% |
| NSL-KDD (KDDTest+) | Random Forest | 76.5% | 96.5% | 60.9% | 0.747 | 0.959 | 2.9% |
| NSL-KDD (KDDTest+) | LightGBM | 77.3% | 96.5% | 62.4% | 0.758 | 0.964 | 3.0% |
| NSL-KDD (KDDTest+) | Autoencoder | 79.8% | 97.4% | 66.4% | 0.789 | 0.953 | 2.4% |
Reading it honestly: precision on NSL-KDD is high (96–98 %) but recall is only 60–66 % because unseen attacks and content-based R2L/U2R attacks dominate the test set and content features are excluded. Synthetic scores are not evidence of real-world accuracy.
All values from the manual’s demo run on synthetic data (manual chapters 6–7, 9, 10). They validate that the pipeline works; retrain on your own baseline before relying on any number.
From chapter 21 of the manual. We publish this because a defense product should be clear about its evidence.
| Item | Status |
|---|---|
| nftables / iptables blocking, release, TTL, rate limit, teardown | Verified with real commands and real TCP connections in an isolated user+network namespace (host network untouched) |
| Engine end-to-end with real nft | Verified in the same namespace: attacker blocked, connection timed out, audit recorded, connection restored after rollback |
| pcap replay, log tail, file watch, CLI, UI over real HTTP | Verified (UI: real HTTP server and requests; firewall = fake backend) |
Live packet sniffing (--iface, root) | Not tested (non-root environment); the same detection code was tested via pcap replay |
Windows netsh blocking | Simulated only — command strings verified, no real Windows |
| Process kill / account lock | Simulated only — fake os.kill / fake executor; gates and protected names verified |
| systemd service example, webhook / syslog delivery | Not tested |
| Large-traffic performance, long-run stability | Not tested — watch the dropped counter after deployment |
| Browser compatibility of the dashboard | Checked in headless Chrome only |
--no-vt if needed.Tell us about your network, hosts and constraints. We will propose a dry-run-first pilot plan — no obligation.