Homelab SOC pipeline: Wazuh Indexer → local threat DB → GreyNoise/OTX/AbuseIPDB → MISP Event 1932 → cautiously filtered VirusTotal community comments. No automatic blocking or VT voting. New automated MISP attributes are not IDS-enabled (to_ids=false) until an analyst reviews them; older attributes are not changed automatically. The MISP new-event helper also defaults to to_ids=false and reports add/publish errors instead of claiming a successful event; partial events require manual review, never automatic promotion.
After the Wazuh 24-hour top-500 source fetch, warninglist_context.py reads four public upstream MISP CIDR warninglists (AWS, Azure, GCP, Cloudflare) over verified HTTPS and writes only source IP/provider-range matches to root-only warninglist-context.json. The local MISP's built-in lists are disabled and some are older; this job does not enable them or write to MISP. A range match is not a benign verdict, an allowlist, independent evidence, or an auto-exclusion. No MISP/VT selection threshold, IDS flag, blocklist, public Pages data, or automated response reads these labels. The report explicitly shows the top-500 coverage limit and upstream list versions; if any list is unavailable, malformed or older than 60 days, the report becomes unavailable with no matches, not a false no-match finding. On a dry run the optional lookup is skipped. The private report is ignored by Git and backed up with root-only archives.
- UTC
06:00and22:00:cron-run.shuses Wazuh → MISP and local NDR/log hunts; it runs the independently capped VT comment job (vt_comment_new.py, at most 3 per run / 6 per UTC day) and generates a dashboard. - GitHub sync publishes privacy-checked
docs/data.json,docs/blocklist.txtanddocs/status.jsonafter a complete run. If any pipeline stage fails,github-sync.sh --status-onlypublishes only a sanitized degraded heartbeat; it does not replace the last safe dashboard snapshot or disclose failure details. A failed dashboard enrichment fallback now fails the snapshot instead of silently publishing empty enrichment; DB-only AS context remains private. GitHub Pages usesdocs/. Code/config changes are not auto-published: review, test, then commit/push manually. - The local detailed dashboard lives in
dashboard/(ignored by Git); privatendr-evidence.jsonretains bounded NDR alert samples and is not committed. Root-onlyreviews.sqlite3records manual IOC review decisions with evidence references and expiry; it never writes to MISP or GitHub and is not an incident/case store. Approvals/revocations still require a separate, verified human action in MISP. Publicdocs/suppresses agent/victim data, raw events and failure details; it shows exact Wazuh totals, whitelisted labels and UTC time of bounded alert samples, full 1932 membership only for displayed source IPs, enrichment lookup age/status, and the 24h pipeline's top-500 coverage limit. Samples are not complete behavior histories. The public watchlist requires MISPto_ids=true, corroborated SSH-source evidence and a non-cloud public IP. Olderto_ids=trueentries are not necessarily analyst-reviewed; one public IP does not mean MISP contains one indicator. The feed is review-only, never a command to block an IP. 02:30 UTC:backup.shwrites a verified, root-only recovery archive to/mnt/storage0/soc-backups(contains secrets; do not upload).backup-health.pychecks the current UTC day's archive after each SOC run; if absent/corrupt/unsafe it triggers the existing failure notification without preventing an otherwise safe public sync.- These UTC times move by one hour in Melbourne during daylight saving. No SSH keys are installed.
| Path | Purpose |
|---|---|
cron-run.sh, backup.sh, backup-health.py, public-status.py, github-sync.sh |
active jobs, public run heartbeat and daily backup monitoring |
src/soc-connector/ |
reviewed snapshot of live skill code; active file is under ~/.config/agents/skills/soc-connector/scripts/ |
src/linux-log-threat-hunt/threat_db.py |
snapshot of DB dependency; active copy lives under the skill |
ioc_comment.py |
one source comment template: fixed public behavior labels, raw rule/target withheld; VT-only fenced summary with references outside the fence (VT Markdown rendering not yet verified) |
warninglist_context.py |
root-only, read-only provider-range context; no actions or sharing |
vt_comment_new.py |
strict, capped VT posting and offline --dry-run preview |
ndr-cross.py, health-check.py, dashboard-gen.py |
bounded private Wazuh/NDR evidence, health and split local/public dashboard |
docs/app.js, themes/issues-to-incidents.html, review-store.py |
safe public DOM rendering; private read-only evidence and local manual IOC reviews (not a case system) |
tests/ |
offline regression/privacy, reviewed-IOC and healthy/degraded/stale-page tests |
config.example.yaml |
placeholder config, never the real config.yaml |
For a manual dry run of the VT selection (no posts):
python3 vt_comment_new.py --dry-run --max 3 --days 7
python3 -m unittest discover -s tests -vbash tests/run-offline.sh runs the Python, JavaScript and shell checks without live SOC credentials, using the reviewed src/ snapshot and pinned PyYAML (requirements-test.txt). GitHub Actions CI is not yet enabled: the current push credential lacks permission to add workflow files. To record a private manual decision: python3 review-store.py record <PUBLIC_SOURCE_IP> --verdict approve_ids --reviewer <ID> --rationale '<20+ character evidence-based reason>' --evidence-ref <PRIVATE_ALERT_REF> --expires <UTC_ISO_TIME>. This does not enable IDS flags in MISP; verify the evidence and make that separate decision in an authenticated MISP session. Expiry and revocation in this ledger do not automatically clear an existing MISP flag; the reviewer must reconcile that state manually. The reviewer identifier is self-declared and this local ledger is not a tamper-proof audited case system.
Live code updates to the skill must be reviewed and copied into src/ before a separate code commit. The local backup contains live code as well. GitHub Pages is not a backup of credentials or state. Event 1932 includes legacy ip-dst entries that were actually observed as inbound sources; newly added attributes use ip-src, and consumers support both during migration.
Contact: admin@kit-cloud.com