InnerWarden 0.16.0
Added
- GuardFall runtime coverage:
find -deletebulk deletion in the data-destruction
detector. The static check-command (above) blocks GuardFall when the agent
proposes the destructive command directly, but a payload hidden in a repo
(aMakefile/script the agent innocently runs) executes as a subprocess the
static hook never sees. The sensor closes that gap because it inspects the REAL,
already-shell-resolved argv the kernel exec'd - sor''m -rf /home/useris
caught on its post-rewrite["rm","-rf","/home/user"]form regardless of the
obfuscation. Thedata_destruction_patterndetector now also fires on an
unfilteredfind <user-data-path> ... -delete(GuardFall class E, the bulk-delete
tool arm-watching blocklist misses), while leaving the ubiquitous filtered
cleanup (find . -name '*.tmp' -delete),/tmp, and build-cache dirs silent - the
same target discrimination therm -rfpath uses, so a maliciousmake test
wiping/home/userfires while a legitmake cleanoftarget/does not.
Added
- GuardFall shell-rewrite defence in the agent-guard check-command engine.
A text/regex blocklist that inspects the command an AI agent proposes is fooled
because the shell REWRITES the command before running it (a class of attack the
GuardFall research showed defeated 10 of 11 open-source coding agents). The
check-command engine (threats::check_command, behind/api/agent/check-command
andiw-guard check) now runs a pure, non-executingnormalize_commandpass that
de-obfuscates the shell rewrites back to their real form before matching: empty-quote
insertion (r''m->rm),$IFSword-splitting (rm$IFS-rf), command substitution
($(echo rm), backticks), variable indirection (${x:-rm}), and backslash escapes
(\r\m). It also adds destructive tools arm-watching blocklist misses (dd of=,
shred,install/cpfrom/dev/null,truncate -s 0,tar -C /) and a
filter-awarefind -deletecheck that blocks an unfiltered bulk delete
(find /path -type f -delete) while leaving the ubiquitous filtered cleanup
(find . -name '*.tmp' -delete) allowed. GuardFall classes A-E now resolve to
deny; the false-positive benchmark ceiling holds (1/18). The normalizer never
spawns a shell or evaluates input and is length- and pass-bounded against DoS.
Highlight: Windows support (Phantom tier)
InnerWarden now runs on Windows, not just Linux/macOS. Two tiers ship: the
per-user AI-agent guardrail (iw-guard: check / serve / enforcing MCP proxy /
one-command Claude Code hook), and the elevated full host tier (install.ps1 -Full: the signed sensor+agent+ctl trio, boot-start Scheduled Tasks, Windows Event
Log (ETW) telemetry -> the 82 detectors -> cloud-AI triage -> dashboard -> Windows
Firewall containment, monitor-only by default). This is the macOS-parity light tier
(spec 085); the kernel EDR (eBPF, Execution Gate) stays Linux-only. Minor version
bump: a new operating-system tier is a feature, not a patch.
Added
install.ps1 -Fullinstalls the Mac-parity Windows host tier (spec 085 Phantom Phase 5). The defaultinstall.ps1still installs only theiw-guardguardrail per-user; the new elevated-Fullmode downloads the signed trio (innerwarden-{sensor,agent,ctl}-windows-x86_64.exe, published by the newbuild-release-windows-fullrelease job), installs to%ProgramFiles%\InnerWardenwith state under%ProgramData%\InnerWarden, writes a Windows monitor-only config (ETW + integrity collectors on, Linux collectors off,[responder] enabled=false dry_run=true), locks the state dir to Administrators/SYSTEM, and registers two boot-start SYSTEM Scheduled Tasks (InnerWarden\innerwarden-{sensor,agent}, the namesctl's systemd.rs restart/status route to) with KeepAlive semantics (ExecutionTimeLimit=0to defeat the 72h auto-kill, 1-min repetition, RestartCount). So a Windows box can now download, install, and boot-start the full light tier: ETW host telemetry -> the 82 detectors -> cloud-AI triage -> dashboard, plus firewall containment via theblock_ip_windowsskill. Apowershell-parseCI job AST-parsesinstall.ps1on every change. Light Scheduled Task, not true SCM (the plain console exes have no ServiceMain); eBPF/Execution Gate stay Linux-only.- Windows now ships the AI-agent guardrail:
iw-guard, a signed, SLSA-attested.exeper release. The guardrail half of InnerWarden (screen an agent's shell command / MCP tool call for danger) is OS-agnostic Rust, so it now runs the same on Linux, macOS, and Windows without the Linux host-EDR (eBPF/sensor/Execution Gate stays Linux-only). A new thin cratecrates/guard-cli(biniw-guard) drives the already-Windows-cleanagent-guardengine with three subcommands:iw-guard check "<cmd>"(verdict JSON, exits 1 ondenyso a PreToolUse hook can gate),iw-guard serve(plain-HTTPPOST /api/agent/check-commandon loopback for an MCP wrapper), andiw-guard proxy --mode guard -- <server>(the enforcing stdio MITM that blocks a disallowedtools/callinline).iw-guard install claude-codewires a fail-closedPreToolUse:Bashhook into Claude Code in one command (offline, in-process): the hook runsiw-guard hook, which reads the tool call on stdin, screens the command locally, and blocks it (exit 2) on adeny(--block-reviewalso blocksreview). It depends only onagent-guard(plus itsmcp_proxy): no sensor, jemalloc, systemd,/proc, or TLS on the check-command path. The newbuild-release-windowsjob publishesiw-guard-windows-x86_64.exe(+ build-only aarch64) with a lowercase SHA-256 sidecar, an Ed25519.sig(same scheme as Linux/macOS), and a Sigstore provenance bundle. Awindows-guardCI job builds + smoke-tests the real.exe(check + serve) on awindows-latestrunner on every guardrail-touching PR.install.ps1fetches, verifies, and installs it. No sensor/agent/detector-count change on Linux. innerwarden audit anchor/innerwarden audit verify— the free CLI for the decision-log external anchor. Wraps theStore::compute_anchor/verify_against_anchorprimitives (shipped 0.15.34) in an operator-facing command:audit anchorprints a compact commitment to the decision log's current tip (seq+ tiprow_hash+count) that the operator records OUTSIDE this host;audit verify --file <anchor.json>(or--anchor '<json>') later proves the live log still contains that exact committed history — verdictIntact/Truncated/Rewritten. This catches the tamper class the internal hash chain cannot: whole-log deletion or a rollback-and-regrow from a fresh (internally-consistent) root, which a rebuilt chain still passes.verifyexits non-zero onTruncated/Rewrittenso it can gate CI or a monitoring probe;--jsonon either subcommand emits machine-readable output, andanchor --jsonround-trips straight intoverify --anchor. Reads the same SQLite store assystem chain-break, so it needs no agent restart. The paidinnerwarden-config-sign auditadds an Ed25519 signature so the anchor is itself tamper-evident off-host; this free form is unsigned (trust rests on where the operator stores it). CLI-only; no sensor/agent/detector-count change.
Security
suspend-user-sudono longer grants the innerwarden user a write-anything-into-/etc/sudoers.d/primitive — the privileged step is now a hard-coded helper subcommand, closing a self-inflicted privilege-escalation path. The response that temporarily revokes a user's sudo has to drop a root-owned file under/etc/sudoers.d/, but the agent runs unprivileged, so it shells out throughsudo. The old grant wasinnerwarden ALL=(ALL) NOPASSWD: /usr/bin/install … <a /tmp file> /etc/sudoers.d/…— i.e. it let the innerwarden user install an arbitrary-content file intosudoers.d, which is full root (writeinnerwarden ALL=(ALL) NOPASSWD: ALL). Worse, the generated grant's path patterns did not even match what the skill actually ran, which is how a box ended up with the over-broadinstall * /etc/sudoers.d/*wildcard just to make suspension work (the exact ruleinnerwarden scannow flags). The fix removes the arbitrary-content primitive entirely: two hidden helper subcommands —innerwarden __sudo-suspend --user <u> --expires <ts>/__sudo-restore --user <u>— generate the drop-in themselves (a fixed deny-all rule,root/uid-0 refused,visudo -cf-validated, atomically installed 0440 root:root), and the sudoers grant is narrowed to only those two subcommands. The only attacker-influenceable input is a username, and the only content that can ever be written is a deny-all rule, so the worst a compromised caller can do through the grant is deny sudo to a non-root user — fail-safe, not escalation. Filename sanitisation, username validation, and the rule body now live once ininnerwarden_core::sudo_guard(shared by the agent skill and the root helper) so "what the agent recorded" and "what root wrote" can never diverge. Existing installs migrate to the narrow grant on the nextharden/ capability re-enable;innerwarden scan(0.15.34) already surfaces any residual over-broad drop-in. Needs a Linux lab pass of the live sudo grant + visudo before deploy. Anchored by tests in all three crates (core: validation/sanitisation/render; ctl: root/root-refusal + 0600 temp + grant-shape asserts; agent: dry-run/TTL/validation/cleanup).
Install / upgrade (Linux, toolchain-free, signed binaries)
curl -fsSL https://innerwarden.com/install | sudo bash
# already installed: sudo innerwarden upgrade --yesEvery binary below is signed (Ed25519 + Sigstore bundle). Docs: https://github.com/InnerWarden/innerwarden/wiki · Site: https://www.innerwarden.com
What's Changed
- chore: adopt the Developer Certificate of Origin by @maiconburn in #1204
- docs(readme): normalize brand, add kernel-gate line and DCO note by @maiconburn in #1205
- deploy/observability: Grafana + Prometheus fleet dashboard by @maiconburn in #1207
- observability: per-agent cost & tokens dashboard row by @maiconburn in #1208
- observability: incident investigation layer (Loki + Alloy) by @maiconburn in #1209
- agent: tenant in agent-guard-events (per-tenant incident investigation) by @maiconburn in #1210
- observability: per-tenant command review + rogue-agent signal (P3) by @maiconburn in #1211
- observability: reusable multi-tenant demo scenario generator by @maiconburn in #1212
- sensor: gate reverse_shell + data_exfil_ebpf behind cloud guest-agent check (Azure ExtHandler FP flood) by @maiconburn in #1213
- observability: tenant on agent_guard incidents + SQLite->Loki bridge by @maiconburn in #1214
- agent-guard: OWASP Agentic Top 10 coverage (reason chain + ASI07 redaction + ASI09 breaker) by @maiconburn in #1215
- docs: remove em-dashes from OWASP coverage doc by @maiconburn in #1216
- perf: cache agent-guard regexes + stream growing jsonl logs (native, zero behaviour change) by @maiconburn in #1217
- perf: drop per-event allocations in the eBPF ring reader + stream /proc/kallsyms by @maiconburn in #1218
- perf: Arc-cache the container identity (cache hit = refcount bump, not a per-event clone) by @maiconburn in #1219
- fix: eliminate two parallel-test flakes (smoke-test transient spawn + registry global counter) by @maiconburn in #1221
- docs: correct the test-count badge (7900+ -> 9800+) by @maiconburn in #1220
- fix: sensor x86_64 build (container_id borrow bound &&str, not &str) by @maiconburn in #1222
- ci: add ebpf-build job to type-check the sensor with deploy features (close the #1222 gap) by @maiconburn in #1223
- fix(sensor): surface a host-blind eBPF sensor instead of reporting active by @maiconburn in #1224
- fix(installer): make agent.env EnvironmentFile optional (fresh install couldn't start the agent) by @maiconburn in #1225
- fix(store): stop "database is locked" ERROR spam on first start (establish WAL before the pool) by @maiconburn in #1226
- feat(guard-cli): iw-guard - the AI-agent guardrail as a cross-platform (Windows-ready) binary by @maiconburn in #1227
- feat(guard-cli): iw-guard proxy - the enforcing MCP guard (Windows-ready) by @maiconburn in #1228
- feat(release): ship iw-guard.exe - signed, attested Windows guardrail per release by @maiconburn in #1229
- feat(guard-cli): iw-guard install claude-code + hook - one-command PreToolUse guard by @maiconburn in #1230
- feat(windows): Phantom Phase 0 - compile-unlock sensor+agent+ctl on windows-msvc by @maiconburn in #1231
- feat(windows): Phantom Phase 1 - ETW/Event-Log telemetry collector by @maiconburn in #1232
- feat(windows): Phantom Phase 2 - block_ip via Windows Firewall skill by @maiconburn in #1233
- feat(windows): Phantom Phase 4 - ctl Scheduled-Task service routing by @maiconburn in #1234
- feat(release): build-release-windows-full - signed, attested Windows trio (Phase 5) by @maiconburn in #1237
- feat(windows): Phantom Phase 5 - install.ps1 -Full (trio install + boot-start) by @maiconburn in #1238
- release: prep v0.16.0 (Windows/Phantom tier) by @maiconburn in #1239
- release: promote development to main (v0.16.0 - Windows/Phantom tier) by @maiconburn in #1240
- fix(release): locate openssl on Windows sign steps (v0.16.0-rc.1 fix) by @maiconburn in #1241
- release: promote development to main (v0.16.0-rc.2 openssl fix) by @maiconburn in #1242
- feat(agent-guard): GuardFall shell-rewrite defence in check-command by @maiconburn in #1243
- release: promote development to main (v0.16.0 GuardFall defence) by @maiconburn in #1244
- feat(sensor): GuardFall runtime coverage - find -delete bulk deletion by @maiconburn in #1245
- fix(sensor): capture execve argv in-kernel (GuardFall runtime, reliable for short-lived procs) by @maiconburn in #1246
- release: promote development to main (v0.16.0 GuardFall runtime + argv capture) by @maiconburn in #1247
Full Changelog: v0.15.34...v0.16.0