Skip to content

Security model

Threat model

The agent is untrusted but mediated: every write and every shell command passes through a harness hook that runs rulewarden. The agent may make mistakes, cut corners, or try to make checks pass by changing the checks. rulewarden defends the rule set, the lock, the hook wiring and the CI configuration (protected paths), and it fails closed on errors in blocking rules.

Out of scope, and listed as limitations: - A harness that does not run the hooks, or ignores onFailure: "block" (for example Codex and Gemini CLI treat hook crashes as fail-open). The git hooks and CI are the backstop. - A human who disables the hooks. This happened during development (DECISIONS.md ADR-010); the hash-chained audit log makes such a gap visible but cannot prevent it. - Running the monitor from the same working copy the agent edits (ADR-015). Install a pinned build for the hooks. - rules.lock cannot vouch for itself without a mediating harness. Without one, protect it with CODEOWNERS and CI.

Engines

Engine Executes Isolation
regex Python re in-process Static ReDoS screen (nested unbounded quantifiers and backreferences rejected at load), input caps, and the whole evaluation runs in a forked child with a wall-clock budget
glob path matching none needed
ast Python ast.parse on the content input caps; parse errors on blocking rules are unverifiable findings, which block
jq the jq binary resolved on PATH, but refused if the resolved binary lies inside the repository (an agent could otherwise plant one); minimal environment; per-check timeout
shell an allowlisted binary opt-in (engines.shell in the protected config); binary looked up only on /usr/bin:/bin; no shell; argv from the locked rule file; scrubbed environment with a temporary HOME/TMPDIR as working directory; per-check timeout
python built-in plugins, or local plugins under .rulewarden/plugins/ built-ins are part of the package. Local plugins are arbitrary code and therefore live under a protected path, so an agent cannot add or change one without a human lock

Not provided: OS-level sandboxing (no network namespace, seccomp or filesystem jail) for shell and jq. A human who allowlists a binary for the shell engine trusts that binary with the user's privileges, network included.

Reporting

Report security issues privately to the repository owner rather than in a public issue.