Skip to content

v0.15.25

Choose a tag to compare

@github-actions github-actions released this 24 Jun 18:51
· 17 commits to main since this release
373bea5

InnerWarden 0.15.25

Security

  • quinn-proto 0.11.14 → 0.11.15 (RUSTSEC-2026-0185). Fixes a remote memory-exhaustion advisory (unbounded out-of-order stream reassembly) in the transitive QUIC dependency. The unrelated tract-onnx 0.22 → 0.23 bump was deliberately NOT taken (breaks the build + would need inference-parity revalidation of the Local Warden classifier for zero security benefit).
  • memmap2 0.9.10 → 0.9.11 (RUSTSEC-2026-0186). Clears an "unchecked pointer offset" unsoundness advisory (published 2026-06-20) in a transitive mmap dependency that only enters the tree with the local-classifier feature. Lockfile-only; cargo deny check is clean (advisories/bans/licenses/sources all ok).
  • rustls 0.23.40 → 0.23.41 and bytes 1.11.1 → 1.12.0. Routine backward-compatible dependency maintenance.

Added

  • Execution Gate can now enforce around just the AI agent (agent-scoped mode, spec 083 eBPF primitive). The Execution Gate is a path-exact allowlist enforced in the kernel; host-wide it fits a locked-down appliance, but a general-purpose server constantly execs legitimate new/transient binaries (dpkg/apt maintainer scripts, certbot renewals, dynamic container workloads), so a host-wide allowlist would block them. New opt-in cgroup scoping lets the gate enforce solely inside the AI agent's process tree and allow everything else unconditionally — "zero-trust for the agent" without touching the rest of the machine. New pinned map EXEC_GATE_SCOPE (/sys/fs/bpf/innerwarden/exec_gate_scope, cgroup id → 1) holds the agent's cgroup id(s); the gate consults LSM_POLICY key 4: when 1, try_exec_gate fires only for tasks whose current cgroup id is in EXEC_GATE_SCOPE and allows every other exec. Key 4 absent/0 = host-wide, the original behaviour, so this is opt-in with no regression. The scope map is repin_preserving so it survives sensor restart; empty-while-scoped is fail-open (the gate never fires), so a wipe is not a brick. Free + INERT in the OSS sensor (key 4 unset); the paid config-sign tooling populates the scope and flips key 4. Verifier-cheap: one map read plus, when scoped, one bpf_get_current_cgroup_id lookup, both patterns already used in the gate hook. eBPF program count unchanged (a new map, not a new program).
  • Mesh-VPN persistence detection is now rename-proof (behavioural TUN/WireGuard signal). The previous exec-name detector (tailscale/zerotier/…) could be evaded by renaming the binary. New tunnel_iface collector (collector #31) watches /sys/class/net for a new tun/WireGuard interface appearing at runtime and classifies by the kernel-set TYPE (uevent: DEVTYPE=wireguard or the tun_flags attribute), not the name — so a renamed mesh-VPN binary is still caught, because the tunnel still has to create a tun/wg interface to route traffic. Interfaces present at startup are baselined (the operator's own VPN), so only a tunnel that comes up later fires. The c2_web_tunnel detector promotes the event to a High, allowlistable ([detectors.c2_web_tunnel]) incident with the same dual-use framing ("legitimate if you started a VPN — allowlist it; if not, it is attacker persistence", T1572/T1219). On by default (AlwaysOnCollectorConfig), 30s poll, deduped on the 600s cooldown. New unit tests pin: WireGuard caught by DEVTYPE even under a non-tunnel name, TUN caught by tun_flags, plain interfaces ignored, and the High mesh_vpn_iface incident. Closes the rename-evasion follow-up tracked when the exec-name detector shipped.
  • innerwarden playbook test --insecure. The agent dashboard serves HTTPS with a self-signed certificate, so innerwarden playbook test --url https://127.0.0.1:8787 … failed with invalid peer certificate: UnknownIssuer and the command could not reach its own agent. The new --insecure flag skips TLS verification for the self-signed cert (documented as not-for-untrusted-networks), so the dry-run playbook test works against the live HTTPS dashboard. Unit-tested for both the verifying and insecure agent-construction paths.
  • n8n integration recipe for the Agent Guard API (docs). New
    docs/integration-recipes/n8n-agent-guard.md shows how to drive the existing
    GET /api/agent/security-context (threat assessment) and
    POST /api/agent/check-command (safety validation) endpoints from an n8n
    workflow: HTTP Request node configuration for each endpoint, the request/response shapes
    and recommendation thresholds (allow/review/deny), and a complete importable
    workflow JSON that halts automatically when the server threat level is elevated or a
    command is denied. Documentation-only — no code or behaviour change. Closes the n8n gap
    noted alongside the existing OpenClaw guide; linked from integrations/README.md.
  • Mesh / overlay-VPN remote-access tools are now detected as a persistence channel (Tailscale, ZeroTier, NetBird, Nebula). Closes a real gap: an attacker who lands on a host can install a mesh VPN (tailscale/tailscaled, zerotier-one/zerotier-cli, netbird, nebula) and SSH back in over the encrypted, NAT-traversing tunnel — stable persistent access that looks like ordinary infrastructure (T1572 protocol tunneling / T1219 remote-access software). Ngrok/Cloudflare/bore/frp/chisel were already covered by c2_web_tunnel; the mesh-VPN family was not. The detector now fires on exec of a known mesh-VPN binary. UX-safe by design because these tools are commonly legitimate: fired at High (not Critical, unlike the C2 tunnels) so it never auto-blocks on its own, exec-only (no coordination-DNS matching, which would be noisy on hosts that legitimately run a mesh VPN), deduped on a 600s cooldown, and allowlistable via [detectors.c2_web_tunnel]; the incident text says plainly "LEGITIMATE if you use it for admin access — allowlist it; if you did NOT install it, it is a common attacker-persistence channel." Anti-gap, honestly scoped: the match is on the exact argv0 basename, so a renamed mesh-VPN binary evades exec-name detection — that limitation is documented in the detector and tracked as a behavioural TUN/WireGuard follow-up (the tunnel still has to create a tun/wg interface, which is the rename-proof signal). New unit tests pin: mesh binaries fire High with sub_kind mesh_vpn, the existing tunnel binaries stay Critical, substring/unrelated binaries stay quiet, and repeat execs are deduped. Detector count unchanged (82 — extends the existing c2_web_tunnel).

Fixed

  • KG decide-modifier (spec 043) is no longer inert — it now measures entity tenure with a clock that survives restarts. The Knowledge-Graph confidence modifier was sitting at modifier_raw=0.0 on essentially every incident in production, so it never did its job (suppressing false positives on long-tenured benign IPs) and could never accumulate the "non-zero would_change_action" data its own promotion gate requires. Root cause: its useful benign-suppression bands gate on first_seen_age_days >= 7, but it read first_seen from the in-memory KG IP node, which is rebuilt from a dated, daily graph snapshot and effectively resets across days/restarts — so the age gate was unreachable. Fix: merge_persisted_profile now overlays the persisted attacker-intel profile (loaded from redb on boot, carrying the true first sighting + composite risk) onto the KG features, taking the OLDER age and HIGHER risk. This makes the age-gated benign bands reachable for genuinely long-lived IPs and keeps the repeat-offender band honest, with no detection weakening (the merge only lengthens tenure / raises risk, never the reverse). Still shadow mode by default — it now produces real signal to validate before any operator flips it to enforce. New unit tests pin the unlock and the never-weakens invariant.
  • InnerWarden no longer flags its OWN egress as a reverse shell (self-FP). The eBPF reverse-shell sequence detector (network.outbound_connect + process.fd_redirect/dup2 within a window, per PID) fired Critical ebpf_reverse_shell incidents on the agent's and CLI's own legitimate outbound connections — Telegram notifications (149.154.166.x), the dashboard API, threat-feed polling — because the agent connects out and dup2's fds in the same process. Observed as ~126 Critical self-flags in 30 minutes on a test box (source comm innerwarden-age / innerwarden); pure noise (it did not auto-block) but it spammed incidents and polluted measurements. Now the sequence detector skips a verified InnerWarden self-process, gated by is_verified_infra_process — i.e. the comm matches innerwarden* AND /proc/<pid>/exe resolves to a real system path. No blind spot: a process that merely sets comm=innerwarden-* but whose exe is /tmp (or anywhere non-system) still fires. Verified via the reliable connect-time comm, so skipping the connect also prevents a later corrupted-comm fd_redirect from firing. Regression tests pin both the self-skip and the forged-comm-still-fires case.

Install / upgrade (Linux, toolchain-free, signed binaries)

curl -fsSL https://innerwarden.com/install | sudo bash
# already installed:  sudo innerwarden upgrade --yes

Every binary below is signed (Ed25519 + Sigstore bundle). Docs: https://github.com/InnerWarden/innerwarden/wiki · Site: https://www.innerwarden.com

What's Changed

  • fix(sensor): stop InnerWarden flagging its own egress as a reverse shell by @maiconburn in #1097
  • feat(sensor): detect mesh/overlay-VPN persistence (tailscale/zerotier/netbird/nebula) by @maiconburn in #1098
  • test(sensor): cover journald collector command and cursor branches by @GordonYuanyc in #1096
  • docs(readme): clarity pass for the top screen (virality + comprehension) by @maiconburn in #1099
  • docs(readme): remove the inline demo video embed by @maiconburn in #1100
  • docs(readme): drop deprecated fail2ban-integration from modules + scan by @maiconburn in #1105
  • build(deps): bump rustls 0.23.41 + bytes 1.12.0 (unified) by @maiconburn in #1104
  • build(deps): bump quinn-proto 0.11.15 (fixes RUSTSEC-2026-0185) by @maiconburn in #1107
  • docs: add n8n integration recipe for Agent Guard API by @Posterfo in #1106
  • feat(ctl): playbook test --insecure for the self-signed dashboard by @maiconburn in #1109
  • feat(sensor): rename-proof mesh-VPN detection (tunnel-interface monitor) by @maiconburn in #1110
  • fix(agent): KG decide-modifier reads persisted tenure (spec 043, un-inert) by @maiconburn in #1111
  • docs(readme): dedupe the middle (Watches/Detects walls) by @maiconburn in #1112
  • feat(sensor): agent-scoped Execution Gate (spec 083, eBPF primitive) by @maiconburn in #1113
  • release: 0.15.25 by @maiconburn in #1108

New Contributors

Full Changelog: v0.15.24...v0.15.25