Kernel-level behavioral monitoring and active vulnerability scanning for AI/ML workloads on Linux.
Akmon is an agentic-security sensor: eBPF-powered observation of every AI process on the box (what it executes, which files it touches, which services it calls), combined with active Nuclei scanning of the local AI stack (Qdrant, Ollama, vLLM, ChromaDB, …) the moment the monitor sees something talk to it.
Two complementary detection engines:
- Behavioral detector — eBPF passive monitoring of syscalls, network events, and file operations matched against YAML rules (our engine, Nuclei-inspired).
- Nuclei active scanner — fires automatically against local AI service endpoints when they're detected, finding real vulnerabilities like unauthenticated vector-DB access.
- eBPF kernel programs — tracepoints for exec, file, network, and mmap events (CO-RE, BTF)
- Behavioral detection engine — YAML template rules (Nuclei-inspired) for process, file, network, and session patterns
- Nuclei v3 integration — active scanning of local AI services when connections are observed
- Session correlation — process tree and session IDs for grouping events
- Output — NDJSON, grouped JSON, or live SSE stream
- Detection templates — shipped in akmon-templates (
behavioral-templates/,nuclei-templates/) - React dashboard (optional) — graph view and alert panel served by the monitor
- Architecture
- Requirements
- Install
- Quick Start
- Build Targets
- Flags
- Configuration (
config.yaml) - Output Format
- Testing
- Detection Templates
- Running as a Background Service (systemd)
- SSE Live Stream
- Project Structure
- Dependencies
- FAQ
┌────────────────────────────────────────────────────────────────┐
│ Kernel (eBPF tracepoints — stable ABI, CO-RE, kernel ≥ 5.15) │
│ execve │ openat │ read/write │ unlinkat │ mmap │ connect │ … │
└─────────────────────────┬──────────────────────────────────────┘
│ ring buffer (8 MB)
┌─────────────────────────▼──────────────────────────────────────┐
│ consumer → decode raw bytes → EnrichedEvent │
│ correlator → assign session ID → process tree + timing │
│ detector → YAML template rules → tags + risk score │
│ │ │
│ └─ net_connect to localhost AI port? │
│ │ │
│ ▼ (async goroutine) │
│ Nuclei engine → scan target → nuclei_finding event │
│ │
│ output → NDJSON / grouped JSON → stdout / file / SSE │
└────────────────────────────────────────────────────────────────┘
| Behavioral Detector | Nuclei Scanner | |
|---|---|---|
| Type | Passive | Active |
| Input | eBPF kernel events | HTTP requests to local services |
| Runs on | Every event | Only net_connect to localhost AI ports (from config.yaml -> ai.services) |
| Detects | Process behavior, file access patterns, cross-event chains | Service misconfigs, unauth access, exposed APIs |
| Output | Tagged EnrichedEvent with risk score |
nuclei_finding event with matched template |
| Latency | Real-time (microseconds) | Async scan (seconds) |
Both detectors fire simultaneously when a connection to a local AI service is observed. The Nuclei scanner does not block the main event loop.
- Linux kernel ≥ 5.15 with BTF enabled (
/sys/kernel/btf/vmlinuxmust exist) - Run as root (or with
CAP_BPF+CAP_PERFMON+CAP_NET_ADMIN) - Go 1.22+ for building
clang/llvm-strip/bpftoolfor eBPF compilation (only needed formake bpf)
YAML detection rules are not in this repository. You will usually want the separate templates bundle: akmon-templates.
Clone both repos, then build from the akmon directory:
git clone https://github.com/ClawGuard-Labs/akmon
git clone https://github.com/ClawGuard-Labs/akmon-templates
cd akmon
make buildThen follow Quick Start and Templates setup to point Akmon at your templates.
If you want Akmon to run as a background service and use /etc/akmon/... paths, use:
sudo make install
sudo make enableSee Running as a Background Service (systemd) for details.
This is an alternative to make install. Akmon still requires a Linux host kernel with BTF enabled; the container loads eBPF into the host kernel, so it must run with elevated privileges and host mounts.
From the akmon repo directory:
git clone https://github.com/ClawGuard-Labs/akmon-templates.git ../akmon-templates
sudo mkdir -p /var/log/akmondocker-compose.yml expects:
./config.yaml-> mounted to/etc/akmon/config.yaml../akmon-templates/behavioral-templates-> mounted to/etc/akmon/behavioral-templates../akmon-templates/nuclei-templates-> mounted to/etc/akmon/nuclei-templates- Host
/var/log/akmon-> mounted to container/var/log/akmon(persistent logs/output)
Using Compose:
docker compose up --buildOr using docker run directly (equivalent shape):
docker build -t akmon:local -f Dockerfile.runtime .
docker run --rm \
--privileged \
--pid=host \
--network=host \
-v /sys/kernel/btf:/sys/kernel/btf:ro \
-v /sys/kernel/tracing:/sys/kernel/tracing \
-v /sys/kernel/debug:/sys/kernel/debug \
-v /sys/fs/bpf:/sys/fs/bpf \
-v /var/log/akmon:/var/log/akmon \
-v "$PWD/config.yaml:/etc/akmon/config.yaml:ro" \
-v "$PWD/../akmon-templates/behavioral-templates:/etc/akmon/behavioral-templates:ro" \
-v "$PWD/../akmon-templates/nuclei-templates:/etc/akmon/nuclei-templates:ro" \
akmon:local- Container logs (stderr/stdout):
docker logs akmon(ordocker compose logs -f). - Event output files (persistent on the host via the mounted directory):
/var/log/akmon/events_logs.json/var/log/akmon/events_rules.json/var/log/akmon/chains.json
The runtime target is Linux only, but contributors can build on macOS using the provided dev image:
docker build -t akmon-dev -f Dockerfile.dev .
docker run --rm -v "$PWD:/src" -w /src akmon-dev make build-no-uiLoading eBPF programs into the kernel requires a Linux host; use a VM, a cloud Linux box, or CI (see .github/workflows/ci.yml) for runtime tests.
Akmon needs two template directories:
- Behavioral:
behavioral-templates/(fromakmon-templates) - Nuclei:
nuclei-templates/(fromakmon-templates)
Choose one of these common layouts.
From the akmon repo directory, defaults expect:
./akmon-templates/behavioral-templates./nuclei-templates(you can symlink it to the bundle)
git clone https://github.com/ClawGuard-Labs/akmon-templates.git akmon-templates
ln -sfn akmon-templates/nuclei-templates ./nuclei-templates # optional: default nuclei pathIf akmon-templates sits next to akmon:
sudo ./bin/akmon \
--behavioral-templates ../akmon-templates/behavioral-templates \
--nuclei-templates ../akmon-templates/nuclei-templatesIf you used Option A (defaults), you can run:
sudo ./bin/akmonMore flags:
sudo ./bin/akmon \
--output events.json \
--log-level info \
--grouped \
--group-timeout 500msSee Detection Templates for authoring and rule bundles.
make build # deps + gen-vmlinux + eBPF + UI + Go -> bin/akmon
make build-no-ui # Same without rebuilding the React UI (faster iteration)
make bpf # Recompile eBPF C -> bpf/monitor.bpf.o (needs vmlinux.h + clang)
make deps # Check deps; on Debian/Ubuntu installs missing apt packages (sudo)
make gen-vmlinux # Regenerate vmlinux.h from kernel BTF (once per kernel)
make ui # Build the React dashboard (requires Node.js ≥ 18)
make run # Build and run as root
make install # Install binary, BPF, templates path, systemd + logrotate (see below)
make clean # Remove bpf/monitor.bpf.o, bin/, embedded UI assets (keeps vmlinux.h, ui/node_modules)
make distclean # make clean + remove bpf/vmlinux.h
make clean-deps # cleans ui/node_modules + Akmon-related apt/snap toolchain (destructive)
make test # go test under tests/
make fmt # go fmt + clang-format on bpf/
make lint # golangci-lint| Flag | Default | Description |
|---|---|---|
--bpf-obj <path> |
auto-detect | Path to monitor.bpf.o. Auto-detected: ./bpf/, next to binary, /usr/lib/akmon/ |
--behavioral-templates <dir> |
./akmon-templates/behavioral-templates |
Directory containing behavioral YAML rules |
--nuclei-templates <dir> |
./nuclei-templates |
Directory containing Nuclei YAML templates for active scanning |
--no-nuclei |
false | Disable active Nuclei scanning |
--output <file> |
stdout | JSON output file (appended) |
--sse <addr> |
disabled | SSE live stream address, e.g. :8080. Connect with curl http://localhost:8080/events |
--grouped |
false | Buffer events by session and flush as one JSON block per session |
--group-timeout <dur> |
500ms |
Idle time before a session group is flushed (only with --grouped) |
--log-level <level> |
info |
Log verbosity: debug | info | warn | error |
--config <path> |
auto-detect | Path to config.yaml (AI services/ports, model extensions, AI process names). If unset, Akmon searches ./config.yaml, then /etc/akmon/config.yaml, then next to the binary. |
--no-tls |
false | Disable TLS uprobe capture (uprobes on libssl.so) |
--cors-origin <url> |
http://localhost:9090, http://127.0.0.1:9090 |
Allowed origins for the dashboard API (repeatable). Defaults cover the local dashboard only. |
--version |
— | Print version and exit |
Akmon ships with a config.yaml that defines the AI profile used at runtime:
ai.services: localhost ports Akmon treats as AI services (used for service labeling and for triggering the Nuclei scanner on observed connections).ai.processes: process names that should be considered AI runtimes/agents (powers theis_ai_processflag used by behavioral rules).ai.model_extensions: model file extensions used by file-access rules (e.g..gguf,.safetensors,.onnx).
Scanned AI service ports:
| Port | Service |
|---|---|
| 6333 | Qdrant |
| 8000 | ChromaDB |
| 8080 | Weaviate |
| 11434 | Ollama |
| 8001 | vLLM |
| 7860 | Gradio |
| 8501 | Streamlit |
| 3000 | LocalAI |
| 19530 | Milvus |
| 9200 | Elasticsearch |
Deduplication: each unique host:port is scanned at most once per 10 minutes.
One JSON line per event:
{"timestamp":"2026-02-21T10:00:01Z","event_type":"exec","pid":12345,"comm":"python3","binary":"/usr/bin/python3","ai_session_id":"sess_a1b2c3d4","risk_score":10,"tags":["ai_process"],"is_ai_process":true}
{"timestamp":"2026-02-21T10:00:02Z","event_type":"net_connect","pid":12345,"comm":"python3","network":{"dst_ip":"127.0.0.1","dst_port":6333,"protocol":"tcp"},"ai_session_id":"sess_a1b2c3d4","risk_score":10,"tags":["outbound_http"]}
{"timestamp":"2026-02-21T10:00:04Z","event_type":"nuclei_finding","pid":12345,"comm":"python3","ai_session_id":"sess_a1b2c3d4","risk_score":70,"tags":["nuclei_finding","qdrant-unauth-access"],"nuclei_result":{"template_id":"qdrant-unauth-access","name":"Qdrant Vector DB Unauthenticated Access","severity":"high","matched_url":"http://127.0.0.1:6333/collections","service":"qdrant"}}All events from a session in one block:
{
"session_id": "sess_a1b2c3d4",
"parent_comm": "bash",
"first_seen": "2026-02-21T10:00:01Z",
"last_seen": "2026-02-21T10:00:30Z",
"duration_ms": 29000,
"peak_risk_score": 80,
"tags": ["ai_process", "outbound_http", "nuclei_finding", "qdrant-unauth-access"],
"event_count": 12,
"events": [ ... ]
}| Score | Severity | Meaning |
|---|---|---|
| 0–20 | Info | Normal AI activity (process start, model load, HTTP request) |
| 21–50 | Low | Minor concern (config access, file deletion, unusual port) |
| 51–75 | Medium | Elevated risk (download+exec chain, sensitive file access) |
| 76–100 | High | Strong indicator (SSH key access, self-modification) |
| 101+ | Critical | Multiple high-risk patterns in same session |
Nuclei findings add their own score on top of the behavioral score.
# Start monitor
sudo ./bin/akmon --log-level debug --output test.json
# In another terminal — trigger rules:
# ai_process + model_load
python3 -c "open('/tmp/model.pt', 'w').close(); open('/tmp/model.pt')"
# ssh_key_access
cat ~/.ssh/id_rsa 2>/dev/null || echo "no key"
# outbound_http
curl -s https://api.openai.com/v1/models -o /dev/null
# curl_bash_chain (high risk)
bash -c "curl -s http://example.com -o /dev/null"
# Check output
cat test.json | jq '.tags'# Start a local Qdrant instance (Docker)
docker run -d -p 6333:6333 qdrant/qdrant
# Start monitor with debug logging
sudo ./bin/akmon --log-level debug --output nuclei_test.json
# Connect something to Qdrant so the monitor sees the port
curl http://localhost:6333/collections
# Within seconds you should see in logs:
# INFO nuclei: scan triggered {"target": "http://127.0.0.1:6333", "service": "qdrant"}
# INFO nuclei finding {"template_id": "qdrant-unauth-access", "severity": "high"}
# Verify in output
cat nuclei_test.json | jq 'select(.event_type == "nuclei_finding")'# The startup logs print which template directories were loaded.
# If you’re unsure which paths Akmon is using, see:
# Templates setup: https://github.com/ClawGuard-Labs/akmon#templates-setup-akmon-templates
sudo ./bin/akmon --log-level info 2>&1 | grep -E "templates loaded|nuclei engine ready|active scanner enabled"Rules are maintained in akmon-templates. YAML-based rules evaluated against every eBPF event. Rules are loaded at startup — no recompilation required to add or modify them.
- Local dev paths: see Templates setup.
- System install paths:
make installcopies templates under/etc/akmon/(see Running as a Background Service (systemd)). - Tests:
go test ./...undertests/expects the templates repo as a sibling (../akmon-templates). Adjusttests/helpers_test.goif your layout differs.
The monitor ships with a systemd unit file. Use make install to install everything system-wide and make enable to start it on boot.
# Full build (eBPF + React UI + Go binary)
make build
# Install binary, BPF object, templates (from TEMPLATES_SRC), and systemd unit
sudo make installmake install places files at:
| Path | Contents |
|---|---|
/usr/local/bin/akmon |
Binary |
/usr/lib/akmon/monitor.bpf.o |
eBPF object |
/etc/akmon/config.yaml |
AI profile used to classify AI processes/services and model file extensions |
/etc/akmon/behavioral-templates/ |
Behavioral detection rules (from akmon-templates) |
/etc/akmon/nuclei-templates/ |
Nuclei active scan templates (from akmon-templates) |
/etc/systemd/system/akmon.service |
systemd unit |
/etc/logrotate.d/akmon |
Log rotation config |
# Enable on boot and start immediately
sudo make enable
# Or manually with systemctl
sudo systemctl enable --now akmon# Service status
sudo systemctl status akmon
# Live logs (journald)
journalctl -u akmon -f
# Output log file (NDJSON events)
tail -f /var/log/akmon/monitor.logsudo systemctl stop akmon
sudo systemctl restart akmon
sudo systemctl disable akmon # removes from boot# Stops the service, disables it, and removes all installed files
sudo make uninstall
# Logs at /var/log/akmon/ are preserved — remove manually if desired
sudo rm -rf /var/log/akmon/The default ExecStart passes the installed template directories and enables the web UI on port 9090:
http://localhost:9090 ← live graph dashboard
# Start monitor with SSE
sudo ./bin/akmon --sse :8080
# Stream events in real-time
curl -N http://localhost:8080/events
# Health check
curl http://localhost:8080/healthzakmon/
├── bpf/
│ ├── monitor.bpf.c # eBPF kernel programs (syscall tracepoints)
│ ├── common.h # Shared kernel/userspace structs and constants
│ ├── vmlinux.h # BTF-generated kernel headers (CO-RE); from scripts/gen_vmlinux.sh
│ └── monitor.bpf.o # eBPF object from `make bpf` / `make build` (also copied under bin/)
├── bin/ # Local build outputs: akmon, monitor.bpf.o (gitignored when built)
├── cmd/monitor/
│ └── main.go # Entry point, flags, config.yaml load, pipeline wiring
├── internal/
│ ├── aiprofile/
│ │ └── config.go # Loads config.yaml (AI services, processes, model extensions)
│ ├── chagg/ # Chain aggregation for --compact / --compact-log
│ ├── constants/ # FileExt, IsLocalhost, IsWriteOpen, SeverityScore, …
│ ├── consumer/ # Ring buffer reader + BPF struct decoder
│ ├── correlator/ # PID tracking, session assignment
│ ├── detector/ # Behavioral YAML loader + Analyze()
│ ├── graph/ # In-memory graph + snapshots + SSE subscribers
│ ├── graphapi/ # Dashboard HTTP server (--ui); go:embed of Vite output
│ │ └── static/ # Built UI assets (`make ui`); cleaned by `make clean`
│ ├── loader/ # eBPF load, tracepoints, optional TLS uprobes / LSM
│ ├── nucleiscanner/ # Nuclei v3 wrapper + localhost service probes
│ ├── output/ # NDJSON, grouped writer, SSE mirror
│ ├── provenance/ # Cross-session file / net_connect taint
│ └── templates/ # Behavioral template YAML schema + loader
├── scripts/
│ ├── docker/
│ │ └── entrypoint.sh # Optional helper for container images
│ ├── akmon.service # systemd unit (installed to /etc/systemd/system/)
│ ├── logrotate.d/akmon # logrotate snippet installed with `make install`
│ ├── bpftool_resolve.sh # bpftool discovery + apt package candidates (sourced by other scripts)
│ ├── check_deps.sh # Build/runtime dependency checks (`make deps`)
│ ├── clean_deps.sh # Toolchain + npm cleanup (`make clean-deps`)
│ └── gen_vmlinux.sh # Generate bpf/vmlinux.h (`make gen-vmlinux`)
├── tests/ # `go test ./tests/...`
├── ui/ # Vite + React dashboard source (`npm install` / `make ui`)
├── assets/ # Screenshots for this README
├── .github/ # Issue/PR templates, CI workflows, CODEOWNERS
├── config.yaml # Default AI profile; install copies to /etc/akmon/config.yaml
├── docker-compose.yml # Local/runtime Compose stack (templates + config mounts)
├── Dockerfile.dev # Linux dev toolchain image (Go + clang + libbpf + Node)
├── Dockerfile.runtime # Minimal runtime image (loads eBPF on host kernel)
├── go.mod
├── go.sum
├── Makefile
├── .golangci.yml # Lint config for `make lint`
├── README.md
├── CONTRIBUTING.md
├── CODE_OF_CONDUCT.md
├── SECURITY.md
├── SUPPORT.md
├── CHANGELOG.md
└── LICENSE
Behavioral and Nuclei YAML live in the separate akmon-templates repository.

Realtime logs (Akmon running as a systemd service)

Real-time process graph visualisation
| Module | Version | Purpose |
|---|---|---|
github.com/cilium/ebpf |
v0.16.0 | eBPF program loading and ring buffer |
github.com/projectdiscovery/nuclei/v3 |
v3.7.0 | Active vulnerability scanning engine |
go.uber.org/zap |
v1.27.0 | Structured logging |
gopkg.in/yaml.v3 |
v3.0.1 | Behavioral template YAML parsing |
| Requirement | Version |
|---|---|
| Linux kernel | ≥ 5.15 with BTF |
| Go toolchain | ≥ 1.22 |
| clang/LLVM | ≥ 14 (for eBPF recompilation only) |
| bpftool | any recent |
/sys/kernel/btf/vmlinux does not exist.
Your kernel wasn't built with CONFIG_DEBUG_INFO_BTF=y. Stock Ubuntu 22.04/24.04 and Debian 12 kernels already have BTF. If you're on a custom kernel, rebuild with CONFIG_DEBUG_INFO_BTF=y and CONFIG_DEBUG_INFO_BTF_MODULES=y.
Permission denied when loading eBPF.
You need one of: run as root, or grant CAP_BPF, CAP_PERFMON, CAP_NET_ADMIN via setcap cap_bpf,cap_perfmon,cap_net_admin+eip ./bin/akmon. Some distros also require sysctl kernel.unprivileged_bpf_disabled=0 for non-root operation.
clang: command not found when running make bpf.
Install the eBPF toolchain (paths vary by kernel flavor): run make deps or see scripts/bpftool_resolve.sh for apt/dnf hints (linux-tools-<uname -r>, linux-tools-azure, linux-cloud-tools-*, linux-tools-generic, bpftool, etc.).
I'm on macOS and make build fails.
Akmon is Linux-only at runtime. Use Dockerfile.dev to build in a container (see Build on macOS), and run the binary on a Linux host.
CI says ../akmon-templates/behavioral-templates missing.
Tests expect the templates repo to live as a sibling directory. Clone it with git clone https://github.com/ClawGuard-Labs/akmon-templates ../akmon-templates (or override TEMPLATES_SRC in the Makefile).
- Report a bug: GitHub Issues
- Propose a feature: GitHub Discussions
- Report a vulnerability: see SECURITY.md
We welcome contributions! Please read CONTRIBUTING.md for development setup, pull request process, and code conventions. By participating, you agree to our Code of Conduct.
This project is licensed under the MIT License — see the LICENSE file for details.
If you discover a security vulnerability, please report it privately. Do not open a public issue. See SECURITY.md for the disclosure process.
