Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "network-guardian"
version = "0.9.0"
version = "0.10.0"
edition = "2021"
description = "Local-first workstation security monitor — protecting the builders"
license = "MIT"
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ network_guardian connections # one-shot process → dest table
network_guardian stack # WSL + Docker (containers, networks, host-port exposure)
network_guardian rules # show YAML policy (v3 allow/deny/CIDR/custom)
network_guardian region # Nepal/South Asia radar + local IoC exposure
network_guardian region packs # list local curated packs (R5, no network)
network_guardian region refresh # force opt-in live feed pull (HTTP GET only)
network_guardian mcp # MCP stdio server for IDE agents
network_guardian stats
Expand Down Expand Up @@ -88,7 +89,7 @@ Tools (read-only): `security_summary`, `list_active_connections`, `list_alerts`,
- **Reverse DNS** (cached) so CDN IPs can map to known hosts / labels
- **Stack hints**: `wsl`, `docker`, `llm-local` from process names + env probe
- **YAML rules v3** (`rules/default.yml`): first-seen, process allow/watch, destination allow/deny, CIDR, custom match rules, fan-out, ports
- **Regional radar** (Nepal / South Asia): sample pack + **opt-in live feeds** (pull-only HTTP, disk cache) + local IoC exposure
- **Regional radar** (Nepal / South Asia): sample pack + **curated local packs (R5)** under `intel/packs/` + **opt-in live feeds** (pull-only HTTP, disk cache) + local IoC exposure
- **Windows tray + autostart**: `serve --tray`, `autostart enable|disable|status` (HKCU Run)
- **MCP stdio server** for coding agents
- **SSE** live ticks (`/api/events`) + dashboard
Expand All @@ -101,8 +102,8 @@ Tools (read-only): `security_summary`, `list_active_connections`, `list_alerts`,

| Phase | Focus |
|-------|--------|
| Now | Dashboard + rules v3 + MCP + Docker exposure + opt-in feeds |
| Next | Curated AktI-Tech packs (R5), headless tray polish |
| Now | Dashboard + rules v3 + MCP + Docker exposure + feeds + curated packs (R5) |
| Next | Headless tray polish, pack auto-update channel (optional) |
| Later | Mobile companion, Microsoft new-device / ARM64 clients |

## Project layout
Expand All @@ -119,6 +120,8 @@ src/
packet_capture.rs Optional pcap path
threat_database.rs SQLite
rules/default.yml Default policy rules
intel/region.yml Regional radar + packs + feed config
intel/packs/ Curated local threat packs (R5, no network)
web/ Dashboard assets (embedded at build)
```

Expand Down
150 changes: 150 additions & 0 deletions intel/packs/akti-builders-v1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
{
"schema_version": 1,
"pack_id": "akti-builders-v1",
"pack_name": "AktI-Tech Builders (NP / South Asia)",
"pack_version": "1.0.0",
"curator": "AktI-Tech",
"kind": "curated",
"region_code": "NP",
"scope": "south_asia",
"status": "watch",
"summary": "Curated AktI-Tech pack for builders on Windows + WSL2 + Docker + local LLMs in Nepal / South Asia. Focuses on developer supply-chain, credential theft, and outbound C2-shaped traffic patterns. Local-only; not an official CERT feed.",
"generated_at": "2026-07-22T00:00:00+00:00",
"industries": [
{
"name": "Builders / Tech",
"score": 78,
"rationale": "Primary audience: freelancers, startups, and remote engineers. Typosquat packages, CI token theft, and IDE/agent tool abuse are the daily risk surface."
},
{
"name": "Finance / Banking",
"score": 68,
"rationale": "Regional phishing remains elevated; builders handling fintech or payroll integrations share the blast radius."
},
{
"name": "Government / NGO",
"score": 52,
"rationale": "Document malware and credential phishing still common; lower direct builder exposure unless contracting in-sector."
},
{
"name": "Telecom",
"score": 42,
"rationale": "SMS social engineering and SIM-related fraud remain regional themes; watch SMS gateways from unexpected processes."
},
{
"name": "Healthcare",
"score": 38,
"rationale": "Ransomware risk is sector-wide; lower volume of open reporting targeted at solo builders."
}
],
"campaigns": [
{
"id": "akti-dev-typosquat-2026",
"title": "Developer package typosquats & post-install beacons",
"severity": "elevated",
"countries": ["NP", "IN", "BD", "LK", "SA"],
"sectors": ["Builders / Tech"],
"summary": "Malicious or typosquat npm/PyPI/Cargo crates that phone home after install. Correlate python/node/cargo/npm to first-seen raw IPs and unknown domains.",
"source_name": "AktI-Tech curated pack",
"source_url": "https://github.com/AktI-Tech/network-guardian",
"confidence": "medium"
},
{
"id": "akti-ci-token-exfil",
"title": "CI / cloud credential exfiltration patterns",
"severity": "elevated",
"countries": ["SA", "NP"],
"sectors": ["Builders / Tech"],
"summary": "Stolen GitHub/GitLab/npm tokens used from unexpected processes. Watch git, gh, glab, node, python hitting unusual hosts shortly after first-seen destinations.",
"source_name": "AktI-Tech curated pack",
"source_url": "https://github.com/AktI-Tech/network-guardian",
"confidence": "medium"
},
{
"id": "akti-llm-tool-pivot",
"title": "Local agent / LLM tool unexpected egress",
"severity": "watch",
"countries": ["SA"],
"sectors": ["Builders / Tech"],
"summary": "Coding agents and local model front-ends may call tool hosts not on your mental allowlist. NetworkGuardian already classifies many LLM destinations; this campaign flags the residual unknown class.",
"source_name": "AktI-Tech curated pack",
"source_url": "https://github.com/AktI-Tech/network-guardian",
"confidence": "low"
},
{
"id": "akti-sa-bank-phish-builders",
"title": "South Asia banking phish via browser (builder laptops)",
"severity": "watch",
"countries": ["NP", "IN", "BD"],
"sectors": ["Finance / Banking", "Builders / Tech"],
"summary": "Personal banking phishing remains high volume. On builder PCs, browser processes to never-before-seen domains around payroll time are worth a glance.",
"source_name": "AktI-Tech curated pack",
"source_url": "https://github.com/AktI-Tech/network-guardian",
"confidence": "low"
}
],
"iocs": [
{
"ioc_type": "domain",
"value": "npmjs-registry-cdn.example",
"tags": ["typosquat", "builders", "curated"],
"source": "akti-builders-v1",
"notes": "Fictional typosquat-style domain for correlator demos — will not match real traffic."
},
{
"ioc_type": "domain",
"value": "pypi-packages-mirror.example",
"tags": ["typosquat", "python", "curated"],
"source": "akti-builders-v1",
"notes": "Fictional PyPI mirror lure for demos."
},
{
"ioc_type": "ip",
"value": "198.51.100.66",
"tags": ["c2-shaped", "documentation", "curated"],
"source": "akti-builders-v1",
"notes": "TEST-NET-2 documentation IP for safe correlation demos (RFC 5737)."
},
{
"ioc_type": "ip",
"value": "203.0.113.77",
"tags": ["c2-shaped", "documentation", "curated"],
"source": "akti-builders-v1",
"notes": "TEST-NET-3 documentation IP for safe correlation demos (RFC 5737)."
},
{
"ioc_type": "domain",
"value": "update-electron-builder.example",
"tags": ["supply-chain", "desktop", "curated"],
"source": "akti-builders-v1",
"notes": "Fictional auto-update host often imitated by malware; demo-only."
},
{
"ioc_type": "domain",
"value": "evil-phish-bank-sa.example",
"tags": ["phishing", "finance", "curated"],
"source": "akti-builders-v1",
"notes": "Shared fictional phish domain with sample pack for merge/dedupe testing."
}
],
"sources": [
{
"name": "AktI-Tech curated builders pack v1",
"url": "intel/packs/akti-builders-v1.json",
"kind": "curated",
"note": "Shipped with NetworkGuardian. Drop updated JSON in intel/packs/ to refresh without rebuild. No auto-network."
},
{
"name": "CERT-In (India) — link only",
"url": "https://www.cert-in.org.in/",
"kind": "cert_link",
"note": "Authoritative regional advisories; not auto-ingested."
},
{
"name": "NCSC Nepal — link only",
"url": "https://www.nepalpolice.gov.np/",
"kind": "cert_link",
"note": "Local LE / cybercrime reporting context; not an automated feed."
}
]
}
14 changes: 13 additions & 1 deletion intel/region.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
# Regional threat radar — opt-in situational awareness
# Privacy: connection data never leaves this PC.
# Live feeds (R2) are HTTP GET pull-only and disabled by default.
# Curated packs (R5) load from intel/packs/ with no network.

enabled: true
region_code: "NP"
scope: "south_asia"
# In-memory snapshot reuse (minutes); feed HTTP cache uses feeds.refresh_minutes
cache_ttl_minutes: 60

# R5 — local curated / operator packs (no HTTP)
packs:
enabled: true
directory: intel/packs
# Empty = load every *.json in directory. Or list pack_id / file stems:
# prefer:
# - akti-builders-v1
prefer: []
# Keep sample pack (intel/np_sa_sample.json) as base layer under curated packs
include_sample: true

feeds:
# Set true (or NG_REGION_FEEDS=1) to pull configured sources.
# Or set NG_REGION_FEED_URL=https://…/pack.json for a single JSON pack.
enabled: false
refresh_minutes: 360
timeout_secs: 15
# user_agent: "NetworkGuardian/0.9 (local-only)"
# user_agent: "NetworkGuardian/0.10 (local-only)"
sources:
# Example JSON pack (same schema as intel/np_sa_sample.json):
# - name: operator-pack
Expand Down
2 changes: 1 addition & 1 deletion src/feeds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};

const CACHE_DIR: &str = "intel/cache";
const DEFAULT_UA: &str =
"NetworkGuardian/0.9 (+https://github.com/AktI-Tech/network-guardian; pull-only; no-upload)";
"NetworkGuardian/0.10 (+https://github.com/AktI-Tech/network-guardian; pull-only; no-upload)";

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FeedsConfig {
Expand Down
52 changes: 48 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod daemon;
mod destinations;
mod feeds;
mod mcp;
mod packs;
mod models;
mod network_monitor;
mod notifications;
Expand Down Expand Up @@ -58,6 +59,7 @@ enum Command {
Rules,
Region,
RegionRefresh,
RegionPacks,
Autostart {
action: AutostartAction,
},
Expand Down Expand Up @@ -120,6 +122,7 @@ async fn main() {
Command::Rules => print_rules(),
Command::Region => print_region(Some(&db)),
Command::RegionRefresh => print_region_refresh(Some(&db)),
Command::RegionPacks => print_region_packs(),
Command::Autostart { action } => run_autostart(action),
Command::Stats => print_stats(&db),
Command::Recent(limit) => print_recent(&db, limit),
Expand Down Expand Up @@ -147,9 +150,10 @@ fn parse_command(args: Vec<String>) -> Result<Command, String> {
"rules" => Ok(Command::Rules),
"region" => match args.get(1).map(|s| s.as_str()) {
Some("refresh") | Some("--refresh") => Ok(Command::RegionRefresh),
Some("packs") | Some("pack") | Some("list-packs") => Ok(Command::RegionPacks),
None | Some("show") | Some("status") => Ok(Command::Region),
Some(other) => Err(format!(
"unknown region action '{other}' (use region | region refresh)"
"unknown region action '{other}' (use region | region refresh | region packs)"
)),
},
"autostart" => {
Expand Down Expand Up @@ -557,6 +561,36 @@ fn print_region_refresh(db: Option<&ThreatDatabase>) {
print_region_inner(db, true);
}

fn print_region_packs() {
let (cfg, list) = crate::region::list_packs();
println!("📦 Local threat packs (R5)");
println!(
" Directory: {} Enabled: {} Include sample: {}",
cfg.directory, cfg.enabled, cfg.include_sample
);
if !cfg.prefer.is_empty() {
println!(" Prefer: {}", cfg.prefer.join(", "));
}
println!(" Env override: NG_REGION_PACKS=0|1");
if list.is_empty() {
println!("\n (no *.json packs found — drop files under {})", cfg.directory);
return;
}
println!();
for p in list {
let flag = if p.loaded { "load" } else { "skip" };
println!(
" [{flag}] {} v{} kind={} iocs={} campaigns={}",
p.id, p.version, p.kind, p.ioc_count, p.campaign_count
);
println!(" {} — {}", p.path, p.message);
if !p.curator.is_empty() {
println!(" curator: {} name: {}", p.curator, p.name);
}
}
println!("\nTip: region (no args) shows the merged snapshot used for correlation.");
}

fn print_region_inner(db: Option<&ThreatDatabase>, force_feeds: bool) {
let rules = RuleConfig::load(None);
let snap = crate::region::snapshot_with_local_opts(db, &rules.process_watchlist, force_feeds);
Expand All @@ -568,11 +602,21 @@ fn print_region_inner(db: Option<&ThreatDatabase>, force_feeds: bool) {
snap.enabled
);
println!(
" Sample pack: {} Live feeds: {}",
snap.is_sample, snap.feeds_enabled
" Sample-only: {} Local packs: {} Live feeds: {}",
snap.is_sample, snap.packs_enabled, snap.feeds_enabled
);
println!("\n{}", snap.summary);
println!("\nDisclaimer: {}", snap.disclaimer);
if !snap.packs_loaded.is_empty() {
println!("\nLocal packs:");
for p in &snap.packs_loaded {
let flag = if p.loaded { "ok" } else { "--" };
println!(
" [{flag}] {} v{} ({}) iocs={} {}",
p.id, p.version, p.kind, p.ioc_count, p.message
);
}
}
if !snap.feed_pulls.is_empty() {
println!("\nFeed pulls:");
for p in &snap.feed_pulls {
Expand Down Expand Up @@ -1083,7 +1127,7 @@ fn print_usage() {
println!(" connections One-shot process → destination table");
println!(" stack WSL distros, Docker containers, adapter tags");
println!(" rules Show loaded YAML policy (v3: allow/deny/CIDR/custom)");
println!(" region [refresh] Nepal/South Asia radar; refresh = force feed pull");
println!(" region [refresh|packs] Nepal/South Asia radar; refresh=force feed pull; packs=list local packs");
println!(" monitor Live packet monitor (needs --features packet-capture)");
println!(" stats Show threat + connection summary");
println!(" recent [limit] Show recent alerts");
Expand Down
Loading
Loading