{"slug": "avai-your-first-ai-antivirus", "title": "Avai – your first AI antivirus", "summary": "Avai, an open-source host telemetry tool that uses large language models to classify threats, has been released. The tool snapshots 26 system corners on macOS and 21 on Linux, enriches findings with up to 17 threat-intel sources, and delivers verdicts with MITRE-aligned categories and remediation steps. Avai operates without an agent contract, SIEM, or cloud control plane, offering a read-only dashboard accessible via a single Docker command.", "body_md": "Know what's actually running on your machines.Open-source host telemetry + LLM threat classifier. One`docker run`\n\n.\n\n`avai`\n\nsnapshots 26 corners of your host on macOS (21 on Linux) —\nprocesses, USB, persistence, file integrity, browser extensions, exec\nevents — enriches each new finding with up to **17 threat-intel\nsources** (VirusTotal, MalwareBazaar, URLhaus, CISA KEV, Shodan,\nAbuseIPDB, OSV, NVD, …), and lets a Claude-class LLM tell you which\nones are worth caring about. Verdicts come back as\n**malicious** / **suspicious** / **unknown** / **benign** with a\nMITRE-aligned category, a confidence, and a one-line remediation.\n\n- No agent contract, no SIEM, no cloud control plane.\n- Dedup by content hash — the same artifact is never sent to the LLM twice.\n- 17 plug-and-play threat-intel sources behind the LLM — see\n; missing keys disable a source cleanly.`.env.example`\n\n- Read-only Flask + HTMX + Chart.js dashboard on\n`:8765`\n\n. - BYO key (\n`ANTHROPIC_API_KEY`\n\n/`CLAUDE_CODE_OAUTH_TOKEN`\n\n), or swap to any litellm-supported provider.\n\n→ Marketing site & screenshots: ** https://getavai.com**\n→ Source:\n\n[https://github.com/iklobato/avai](https://github.com/iklobato/avai)\n\nA read-only Flask + HTMX + Chart.js dashboard on `:8765`\n\n. Every panel renders\nfrom the same SQLite snapshot the monitor writes — no separate control plane.\n\nAt-a-glance health: runs stored, collectors in the latest cycle (with any\nfailures), judgments since the last run, and the verdict-totals donut\n(malicious / suspicious / unknown / benign). The macOS **System Integrity** panel\nsurfaces FileVault, Firewall, Gatekeeper and remote-access toggles; **Collector\nErrors** shows what failed (e.g. a TCC permission); and the 12-hour chart tracks\nverdicts over time. The findings table below streams the active, non-benign\nresults.\n\nThe findings table is filterable by status, verdict, collector and category.\nBeneath it, **Rows per collector** shows how much each collector pulled in the\nlatest run, and **Recent runs** lists run history with ok/failed counts and the\nlook-back window.\n\nExpand any finding to see the LLM's **reasoning**, a concrete **remediation**\nstep, and the exact **collected data** behind the verdict — for a process that\nmeans pid/ppid, the full `cmdline`\n\n, the running user/uid, status, the content\nhash used for dedup, and when it was first judged vs. last seen.\n\nThe tcpdump aggregator groups traffic by destination so the classifier can reason\nabout it: here an IPv6 connection to an unusual high port is flagged\n**suspicious** as a possible C2 beacon, while CDN, mDNS and LAN traffic come back\n**benign** — each with a one-line \"why\".\n\nThe same view enriched per destination with the owning **process**, ASN/geo,\ntraffic volume, and the rationale for each verdict.\n\nRun against a different host/cycle — 61 runs and 3,426 verdicts here — with suspicious AirWatch/MDM persistence surfaced for review.\n\n| Run | Command | Where it makes sense |\n|---|---|---|\n| Dashboard (default) | `docker run iklob1/avai` |\nany host — read-only Flask + HTMX on :8765 |\n| Monitor | `docker run ... iklob1/avai avai monitor ...` |\nLinux hosts only — needs `pid=host` , `network=host` , and host filesystem bind-mounts |\n\nThe image's default `CMD`\n\nis the dashboard. Override the command at\n`docker run`\n\n/ compose level to run the monitor instead. Native install\nis also possible (`pip install avai-monitor`\n\n, then `avai monitor`\n\n/\n`avai dashboard`\n\n) but is not the documented path.\n\nThe image carries a `HEALTHCHECK`\n\nagainst the dashboard's\n`/api/notifications/new`\n\nendpoint — `starting → healthy`\n\nin ~10 s on\nfirst launch. `docker compose ps`\n\nand `docker inspect --format '{{.State.Health.Status}}'`\n\nwill both reflect it.\n\nA safe first run on any host (macOS or Linux), no privileges, no credentials, no host bind-mounts. Produces a populated DB and a green dashboard you can poke at.\n\n```\nmkdir -p ~/.avai && cd ~/.avai\n\n# 1. populate the DB with one snapshot of the container's view\ndocker run --rm -v \"$PWD\":/data iklob1/avai \\\n  avai monitor --once --no-streaming --no-judge --db /data/avai.db\n\n# 2. serve it\ndocker run -d --name avai -p 8765:8765 -v \"$PWD\":/data iklob1/avai\n\nopen http://localhost:8765/      # macOS;  xdg-open on Linux\n```\n\nYou'll see ~14 collectors' worth of rows (`processes`\n\n,\n`network_connections`\n\n, `listening_ports`\n\n, `network_interfaces`\n\n,\n`usb_devices`\n\n, `launch_items`\n\n, `installed_apps`\n\n, `mounts`\n\n,\n`setuid_files`\n\n, etc.) — read off the container itself rather than the\nhost, since the run above doesn't bind-mount host state. To get real\ndata, jump to §2 / §3 below.\n\nStop with `docker stop avai && docker rm avai`\n\n.\n\nThe dashboard reads a SQLite database written by the monitor (or by a\nprevious run). It needs no privileges, no host namespace, no\ncapabilities — just a directory containing `avai.db`\n\nmounted at `/data`\n\n.\n\n```\nmkdir -p ~/.avai && cd ~/.avai\n\ndocker run -d \\\n  --name avai-dashboard \\\n  -p 8765:8765 \\\n  -v \"$PWD\":/data \\\n  iklob1/avai\n\nopen http://localhost:8765/\n```\n\nIf the database file doesn't exist yet, the dashboard creates an\nempty schema on launch and every panel renders empty until the\nmonitor produces rows. Stop with `docker stop avai-dashboard && docker rm avai-dashboard`\n\n.\n\n```\ndocker run --rm -p 9000:9000 \\\n  -v /var/lib/avai:/data \\\n  iklob1/avai \\\n  avai dashboard --host 0.0.0.0 --port 9000 --db /data/custom.db\n```\n\nThe image entry point is `avai`\n\n; anything after the image name is\npassed to it.\n\nA single cycle on the local Linux host. No streaming, no LLM judge — fast smoke test that the bind mounts are wired right.\n\n```\nmkdir -p ~/.avai && cd ~/.avai\n\ndocker run --rm \\\n  --pid=host \\\n  --network=host \\\n  --user 0:0 \\\n  --cap-add SYS_PTRACE --cap-add NET_ADMIN --cap-add NET_RAW --cap-add DAC_READ_SEARCH \\\n  -e HOST_PREFIX=/host \\\n  -v /proc:/host/proc:ro \\\n  -v /sys:/host/sys:ro \\\n  -v /etc:/host/etc:ro \\\n  -v /var/lib/bluetooth:/host/var/lib/bluetooth:ro \\\n  -v /var/lib/dpkg:/host/var/lib/dpkg:ro \\\n  -v /usr/share/applications:/host/usr/share/applications:ro \\\n  -v /lib/systemd:/host/lib/systemd:ro \\\n  -v /usr/lib/systemd:/host/usr/lib/systemd:ro \\\n  -v /run/systemd:/run/systemd:ro \\\n  -v /run/dbus:/run/dbus:ro \\\n  -v /etc/machine-id:/etc/machine-id:ro \\\n  -v /dev/mapper:/dev/mapper:ro \\\n  -v /home:/host/home:ro \\\n  -v /root:/host/root:ro \\\n  -v \"$PWD\":/data \\\n  iklob1/avai \\\n  avai monitor --once --no-streaming --no-judge --db /data/avai.db\n```\n\nWhen the command exits, `~/.avai/avai.db`\n\ncontains one\n`collection_runs`\n\nrow plus the populated collector tables. Verify:\n\n``` python\ndocker run --rm -v \"$PWD\":/data iklob1/avai python -c \"\nimport sqlite3\nc = sqlite3.connect('/data/avai.db')\nfor n, in c.execute(\\\"select name from sqlite_master where type='table'\\\"):\n    print(f'{n:<22} {c.execute(f\\\"select count(*) from {n}\\\").fetchone()[0]}')\"\n```\n\nTo smoke-test on macOS without the bind-mounts (no host data, but proves the toolchain works) see §0 above.\n\nSame bind mounts as §2 but detached, with the LLM judge enabled. The\njudge needs one credential — either `ANTHROPIC_API_KEY`\n\n(standard\nAnthropic API) or `CLAUDE_CODE_OAUTH_TOKEN`\n\n(Claude Code OAuth) — and\ndefaults to **Claude Haiku 4.5** (`claude-haiku-4-5-20251001`\n\n).\nOverride with `--judge-model`\n\nto point litellm at any other provider.\n\nThreat-intel enrichment runs automatically with whatever keys are in\nthe environment (`VT_API_KEY`\n\n, `ABUSE_CH_AUTH_KEY`\n\n, `ABUSEIPDB_API_KEY`\n\n,\n…). Easiest pattern is a project-local `.env`\n\n:\n\n```\ncp .env.example .env  &&  vi .env       # fill in only the keys you have\ndocker run -d --env-file .env --name avai-monitor ... iklob1/avai\n```\n\nSee **§ Threat-intel enrichment** below for the full source list and\neach source's gate condition.\n\n```\nmkdir -p ~/.avai && cd ~/.avai\n\ndocker run -d --name avai-monitor --restart unless-stopped \\\n  --pid=host --network=host --user 0:0 \\\n  --cap-add SYS_PTRACE --cap-add NET_ADMIN --cap-add NET_RAW --cap-add DAC_READ_SEARCH \\\n  -e HOST_PREFIX=/host \\\n  -e DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket \\\n  -e ANTHROPIC_API_KEY \\\n  -v /proc:/host/proc:ro -v /sys:/host/sys:ro -v /etc:/host/etc:ro \\\n  -v /var/lib/bluetooth:/host/var/lib/bluetooth:ro \\\n  -v /var/lib/dpkg:/host/var/lib/dpkg:ro \\\n  -v /usr/share/applications:/host/usr/share/applications:ro \\\n  -v /lib/systemd:/host/lib/systemd:ro \\\n  -v /usr/lib/systemd:/host/usr/lib/systemd:ro \\\n  -v /var/log/journal:/host/var/log/journal:ro \\\n  -v /var/spool/cron:/host/var/spool/cron:ro \\\n  -v /run/systemd:/run/systemd:ro -v /run/dbus:/run/dbus:ro \\\n  -v /etc/machine-id:/etc/machine-id:ro \\\n  -v /dev/mapper:/dev/mapper:ro \\\n  -v /home:/host/home:ro -v /root:/host/root:ro \\\n  -v \"$PWD\":/data \\\n  iklob1/avai \\\n  avai monitor --db /data/avai.db --interval 300\n\ndocker logs -f avai-monitor      # watch the cycle\n```\n\nDefaults baked into `avai monitor`\n\n:\n\n| Flag | Default | Effect |\n|---|---|---|\n`--interval` |\n`300` |\nseconds between snapshot cycles |\n`--lookback-min` |\n`6` |\nminutes of journal/log history per run |\n`--max-db-mb` |\n`1024` |\nrotation cap (0 disables); oldest runs are pruned + `VACUUM` 'd after each cycle |\n`--judge-model` |\n`claude-haiku-4-5-20251001` |\nany litellm model id |\n`--judge-batch-size` |\n`20` |\nentries per LLM call |\n`--judge-max-per-collector` |\n`25` |\nper-cycle cap of new entries judged per collector |\n`--no-streaming` |\n(off) | disables `auth_events` + `process_exec_events` tailers |\n`--no-judge` |\n(off) | runs collectors but stores no verdicts |\n`--no-enrich` |\n(off) | skips the whole threat-intel layer; collectors → judge directly |\n`--enrich-only NAME` |\n(all) | restrict the chain to one named source (repeatable); useful for debugging |\n\nAppend any flag to the `docker run … iklob1/avai avai monitor …`\n\ncommand to override. Full reference: `docker run --rm iklob1/avai avai monitor --help`\n\n.\n\n`docker-compose.yml`\n\n:\n\n```\nx-avai-image: &avai-image\n  image: iklob1/avai:latest\n\nservices:\n\n  monitor:\n    <<: *avai-image\n    container_name: avai-monitor\n    command: [\"avai\",\"monitor\",\"--db\",\"/data/avai.db\",\"--interval\",\"300\"]\n    user: \"0:0\"\n    pid: host\n    network_mode: host\n    cap_add: [SYS_PTRACE, NET_ADMIN, NET_RAW, DAC_READ_SEARCH]\n    # Loads LLM-judge + every threat-intel API key from .env. Copy\n    # .env.example to .env and fill in only the keys you have.\n    env_file: [.env]\n    environment:\n      - HOST_PREFIX=/host\n      - DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket\n    volumes:\n      - ./data:/data\n      - /proc:/host/proc:ro\n      - /sys:/host/sys:ro\n      - /etc:/host/etc:ro\n      - /var/lib/bluetooth:/host/var/lib/bluetooth:ro\n      - /var/lib/dpkg:/host/var/lib/dpkg:ro\n      - /usr/share/applications:/host/usr/share/applications:ro\n      - /lib/systemd:/host/lib/systemd:ro\n      - /usr/lib/systemd:/host/usr/lib/systemd:ro\n      - /var/log/journal:/host/var/log/journal:ro\n      - /var/spool/cron:/host/var/spool/cron:ro\n      - /run/systemd:/run/systemd:ro\n      - /run/dbus:/run/dbus:ro\n      - /etc/machine-id:/etc/machine-id:ro\n      - /dev/mapper:/dev/mapper:ro\n      - /home:/host/home:ro\n      - /root:/host/root:ro\n    restart: unless-stopped\n\n  dashboard:\n    <<: *avai-image\n    container_name: avai-dashboard\n    # uses the image's default CMD\n    ports: [\"8765:8765\"]\n    volumes: [\"./data:/data\"]\n    restart: unless-stopped\n```\n\nThen:\n\n```\nmkdir -p data\ncp .env.example .env  &&  vi .env       # fill in the keys you have\ndocker compose up -d\ndocker compose logs -f monitor\nopen http://localhost:8765/\n```\n\nIf you already have an `avai.db`\n\n(produced by the monitor on a\ndifferent machine, dropped into the current directory, etc.):\n\n```\ndocker run --rm -p 8765:8765 -v \"$PWD\":/data iklob1/avai\n```\n\nThe dashboard opens the file with `?mode=ro&immutable=1`\n\n, so it never\nwrites and never holds a lock — fine to point at a live database\nbeing written by the monitor in another container.\n\n```\n# Inspect the bundled CLI\ndocker run --rm iklob1/avai avai --help\ndocker run --rm iklob1/avai avai monitor --help\ndocker run --rm iklob1/avai avai dashboard --help\ndocker run --rm iklob1/avai avai --version\n\n# Healthcheck + status\ndocker inspect avai-dashboard --format '{{.State.Health.Status}}'   # healthy|unhealthy|starting\ndocker compose ps                                                   # if using compose\ndocker logs -f avai-monitor                                         # follow monitor cycles\n\n# DB rotation in action — watch the size cap kick in\ndocker exec avai-monitor du -h /data/avai.db\n\n# Stop / clean up\ndocker compose down                                                  # if using compose\ndocker stop avai-dashboard avai-monitor 2>/dev/null\ndocker rm   avai-dashboard avai-monitor 2>/dev/null\n\n# Wipe the database (also wipes verdicts; monitor will re-judge from scratch)\nrm -f data/avai.db data/avai.db-wal data/avai.db-shm\n\n# Pull the latest image\ndocker pull iklob1/avai\n```\n\nPractical, copy‑paste scenarios beyond the basics above.\n\nInside a container on a real Linux host the monitor already works, but the simplest way to watch a server is to install it natively and let it see everything directly:\n\n```\npip install 'avai-monitor[judge]'          # [judge] pulls litellm + anthropic\nexport ANTHROPIC_API_KEY=sk-ant-...         # or CLAUDE_CODE_OAUTH_TOKEN\nexport ABUSE_CH_AUTH_KEY=...                # optional, free — adds 3 sources\n\nsudo -E avai monitor --db /var/lib/avai/avai.db --interval 300 &\navai dashboard --db /var/lib/avai/avai.db --host 0.0.0.0 --port 8765\n```\n\n`sudo`\n\nlets the collectors read root‑owned state (`/etc/shadow`\n\n,\nother users' crontabs, every process). `-E`\n\npreserves your API keys\nacross the sudo boundary.\n\n`/etc/systemd/system/avai.service`\n\n:\n\n```\n[Unit]\nDescription=avai host monitor\nAfter=network-online.target\n\n[Service]\nEnvironment=ANTHROPIC_API_KEY=sk-ant-...\nEnvironment=ABUSE_CH_AUTH_KEY=...\nExecStart=/usr/local/bin/avai monitor --db /var/lib/avai/avai.db --interval 300\nRestart=always\nUser=root\n\n[Install]\nWantedBy=multi-user.target\nsudo systemctl enable --now avai\njournalctl -u avai -f          # watch cycles\n```\n\nEverything lives in one SQLite file, so you can query it directly — handy for scripting, cron mail, or a server with no browser:\n\n```\n# The active dangerous + suspicious findings, newest first\nsqlite3 -box /var/lib/avai/avai.db \"\n  SELECT verdict, collector, substr(reasoning,1,60) AS why\n  FROM judgements\n  WHERE verdict IN ('malicious','suspicious')\n  ORDER BY created_at DESC LIMIT 20;\"\n\n# Count by verdict\nsqlite3 /var/lib/avai/avai.db \\\n  \"SELECT verdict, count(*) FROM judgements GROUP BY verdict;\"\n\n# What did the threat-intel sources say?\nsqlite3 -box /var/lib/avai/avai.db \"\n  SELECT source, verdict_hint, substr(summary,1,70)\n  FROM enrichment_evidence\n  WHERE verdict_hint IN ('malicious','suspicious');\"\n# /etc/cron.d/avai — scan once an hour, no streaming\n0 * * * * root ANTHROPIC_API_KEY=sk-ant-... \\\n  avai monitor --once --no-streaming --db /var/lib/avai/avai.db\n```\n\nThe monitor writes the DB; the dashboard only reads it. Sync the file (rsync/scp/NFS) and view it anywhere:\n\n```\n# on the server (writer)\navai monitor --db /var/lib/avai/avai.db --interval 300\n\n# pull it to your laptop and view (reader — any OS, no privileges)\nscp server:/var/lib/avai/avai.db ./avai.db\ndocker run --rm -p 8765:8765 -v \"$PWD\":/data iklob1/avai\navai monitor \\\n  --judge-model claude-haiku-4-5-20251001 \\   # cheapest tier (default)\n  --judge-max-per-collector 20 \\              # cap new items judged per cycle\n  --judge-batch-size 20                        # entries per API call\n```\n\nCost is near‑zero in steady state anyway — only *new* artifacts are\njudged, and threat‑intel verdicts are cached, so quiet hosts make\nalmost no API calls after the first cycle.\n\n```\navai monitor --no-enrich                       # collectors + judge only\navai monitor --enrich-only cisa_kev            # just this source (repeatable)\navai monitor --enrich-only virustotal --enrich-only abuseipdb\n```\n\nSource names: `malware_bazaar`\n\n`urlhaus`\n\n`threatfox`\n\n`circl_hashlookup`\n\n`shodan_internetdb`\n\n`feodo_tracker`\n\n`osv`\n\n`cisa_kev`\n\n`nvd`\n\n`endoflife`\n\n`crtsh`\n\n`virustotal`\n\n`abuseipdb`\n\n`greynoise`\n\n`safe_browsing`\n\n`phishtank`\n\n`github_advisory`\n\n.\n\n`--judge-model`\n\nis a [litellm](https://docs.litellm.ai/docs/providers)\nmodel id, so any supported provider works:\n\n```\navai monitor --judge-model gpt-4o-mini            # OpenAI (OPENAI_API_KEY)\navai monitor --judge-model ollama/llama3.1        # local, free, offline\navai monitor --judge-model gemini/gemini-1.5-pro  # Google\n```\n\nSnapshot collectors (run every cycle, default 300s):\n\n| Group | Sources |\n|---|---|\n| Processes / network | `processes` , `network_connections` , `listening_ports` , `network_interfaces` (psutil) |\n| Hardware | `usb_devices` (/sys/bus/usb), `bluetooth_devices` (/var/lib/bluetooth), `wifi_state` (sysfs + `iw` ) |\n| Persistence | `launch_items` (systemd unit files + cron) |\n| Files | `file_integrity` (passwd / shadow / sudoers / SSH config / dotfiles), `setuid_files` , `mounts` |\n| Apps | `installed_apps` (dpkg-query + XDG `.desktop` ), `browser_extensions` |\n| Posture | `system_integrity` (SELinux / AppArmor / ufw / sshd / vnc / LUKS) |\n| Posture (macOS only) | `tcc_permissions` (camera/mic/location/screen grants), `quarantine_events` , `mdm_profiles` , `kernel_extensions` , `system_extensions` |\n\nStreaming collectors (events as they happen):\n\n| Collector | Source |\n|---|---|\n`auth_events` |\n`journalctl -f` (Linux) / macOS unified log (macOS), filtered to security-relevant subsystems. LLM-judged by unique `(process, subsystem, message)` pattern — each event template is classified once regardless of how many times it fires. |\n`process_exec_events` |\n`journalctl -f _AUDIT_TYPE_NAME=EXECVE` (needs auditd `auditctl -a always,exit -F arch=b64 -S execve` rule) |\n\nFor every entity collected (deduped by a content hash over the\ncollector's \"judge fields\"), the LLM judge classifies it as\n`malicious`\n\n/ `suspicious`\n\n/ `unknown`\n\n/ `benign`\n\nwith a confidence,\nMITRE-aligned category, and one-line remediation. Judgments are\npersisted; the same artifact is never sent twice.\n\nThe Flask + HTMX dashboard at `:8765`\n\nhas full filter and pagination on every table:\n\n**Findings**— filter by verdict, collector, category, status (active/resolved), free-text search; sortable columns; configurable page size (10/25/50/100).**Network flows**— filter by verdict and IP/host/process search; summary stats (destinations, volume, malicious count).** Listening ports**— filter by verdict and bind scope (all interfaces / routable / loopback); process search.** DNS queries**— filter by verdict, resolution level (DoH / external DNS / local resolver), domain search.** Persistence**— SSH authorized keys,`/etc/hosts`\n\nmappings, and privilege config each with independent pagination.**Auth events**— aggregated by unique`(process, subsystem, message)`\n\npattern with occurrence counts and last-seen timestamps. Filter by subsystem (TCC, securityd, syspolicy, loginwindow, Authorization) or verdict. Sort by count or verdict severity. LLM verdicts appear as patterns are classified.**TCC permissions**(macOS) — every app's camera, microphone, location, screen-recording, and full-disk-access grant/denial, with LLM verdict and auth-status filter.\n\nAll sections auto-refresh (30–60 s). Toast notifications + audio alert fire for new malicious/suspicious judgments.\n\nBefore each finding hits the LLM, avai extracts indicators (SHA256, IPv4, domain, URL, CVE, package, OS version) and runs them through external threat-intel APIs. The judge then sees the raw evidence inline in the prompt, which dramatically tightens verdicts.\n\nEvery source is optional. Keyless ones always run. Keyed ones only\nregister if the env var below is set — see [ .env.example](/iklobato/avai/blob/release/0.1.0/.env.example)\nfor a copy-paste template.\n\n| Source | Indicator | Env var | Quota | What it adds |\n|---|---|---|---|---|\nMalwareBazaar (abuse.ch) |\nSHA256/1/MD5 | `ABUSE_CH_AUTH_KEY` |\nunlimited | Known-malware family |\nCIRCL hashlookup (NSRL) |\nSHA256/1/MD5 | — | unlimited | Known-good vendor binary (whitelist) |\nShodan InternetDB |\nIPv4 | — | 1 rps | Open ports, CVEs, tags |\nURLhaus (abuse.ch) |\nURL, domain | `ABUSE_CH_AUTH_KEY` |\nunlimited | Malware-distribution URLs |\nFeodo Tracker (abuse.ch) |\nIPv4 | — | unlimited | Botnet C2 IPs (cached feed) |\nThreatFox (abuse.ch) |\nIPv4 / domain / URL / hash | `ABUSE_CH_AUTH_KEY` |\nunlimited | Mixed IOC search |\nOSV.dev |\nCVE, package | — | unlimited | Open-source advisories |\nCISA KEV |\nCVE | — | static feed | Actively-exploited CVEs |\nNVD |\nCVE | `NVD_API_KEY` (optional) |\n5 → 50 / 30 s | CVSS + description |\ncrt.sh |\ndomain | — | gentle | Certificate transparency history |\nendoflife.date |\nOS version | — | unlimited | EOL'd OS / runtime |\nVirusTotal |\nSHA256/1/MD5, URL, domain, IPv4 | `VT_API_KEY` |\n4/min, 500/day | Multi-engine reputation |\nAbuseIPDB |\nIPv4 | `ABUSEIPDB_API_KEY` |\n1000/day | Abuse confidence score |\nGreyNoise Community |\nIPv4 | `GREYNOISE_API_KEY` |\n50/day | \"Is this IP just noise?\" |\nGoogle Safe Browsing |\nURL | `GOOGLE_SAFE_BROWSING_API_KEY` |\n10k/day | Phishing / malware verdict |\nPhishTank |\nURL | `PHISHTANK_API_KEY` |\ngenerous | Community phishing DB |\nGitHub Advisory |\nCVE | `GITHUB_TOKEN` |\nhigh | Curated advisories + fix versions |\n\nPer-indicator results are cached in the same SQLite (`enrichment_evidence`\n\ntable) with a per-source TTL (6 h – 14 d). Fresh cache hits skip the\nnetwork entirely; the cache survives restarts.\n\nToggle with:\n\n```\navai monitor                              # all enabled sources, default\navai monitor --no-enrich                  # collectors + judge, no external lookups\navai monitor --enrich-only malware_bazaar # debugging: only this one\n```\n\nThe monitor relies on Linux-native facilities — `pid=host`\n\nreaching\nthe host's `/proc`\n\n, sysfs at `/sys/bus/usb`\n\n, `journalctl`\n\nwith\n`auditd`\n\n, `systemctl is-active`\n\n, `dpkg-query`\n\n, `dmsetup`\n\nfor LUKS.\nDocker Desktop on macOS only exposes the Linux VM it ships with, not\nthe macOS host, so a containerised monitor on macOS reports on the VM\n(empty/uninteresting) rather than the Mac. The dashboard role works\nfine on macOS Docker — you'd just need to write the database from\nsomewhere else.\n\nIf you want full macOS coverage, install natively (`pip install avai-monitor`\n\n) and run `avai monitor`\n\nwith `sudo`\n\n. That's a separate\npath not documented here.\n\nThe suite is network-free and runs in seconds. The repo's dev Python may carry plugin conflicts, so run it in a throwaway venv:\n\n```\npython3 -m venv /tmp/venv && /tmp/venv/bin/pip install -e . pytest\n/tmp/venv/bin/python -m pytest tests/ -q       # 320+ unit tests\n```\n\nCoverage spans the enrichment framework and all 18 sources, the\nindicator extractors, the HTTP client (rate limit / backoff / 429),\nthe CLI dispatcher, the SQLAlchemy repository + DB rotation, the LLM\njudge's parsing, the dashboard endpoints, and the Linux collectors'\nfile parsing (systemd / cron / `.desktop`\n\n/ BlueZ). Tests are written\nto fail when the implementation breaks — verified by mutation testing,\nnot just coverage percentage.\n\nUnattended Docker smoke test (builds the image, runs the CLI surface, a cold collector pass, and the keyless-enrichment registry check):\n\n```\ntests/local.sh            # all phases; exits non-zero on any failure\n```\n\nSee [ CHANGELOG.md](/iklobato/avai/blob/release/0.1.0/CHANGELOG.md) for version history.\n\nMIT — see `LICENSE`\n\n.", "url": "https://wpnews.pro/news/avai-your-first-ai-antivirus", "canonical_source": "https://github.com/iklobato/avai", "published_at": "2026-05-30 02:11:14+00:00", "updated_at": "2026-05-30 02:45:51.434712+00:00", "lang": "en", "topics": ["ai-products", "ai-tools", "ai-infrastructure", "artificial-intelligence", "large-language-models"], "entities": ["Avai", "VirusTotal", "MalwareBazaar", "URLhaus", "CISA KEV", "Shodan", "AbuseIPDB", "OSV"], "alternates": {"html": "https://wpnews.pro/news/avai-your-first-ai-antivirus", "markdown": "https://wpnews.pro/news/avai-your-first-ai-antivirus.md", "text": "https://wpnews.pro/news/avai-your-first-ai-antivirus.txt", "jsonld": "https://wpnews.pro/news/avai-your-first-ai-antivirus.jsonld"}}