Skip to content

release: 0.1.2 — a wrapped command no longer escapes the guardrail, and the policy watches itself - #35

Merged
djayamah merged 1 commit into
mainfrom
release-0.1.2
Sep 8, 2026
Merged

djayamah merged 1 commit into
mainfrom
release-0.1.2

Conversation

@djayamah

@djayamah djayamah commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Two security fixes and one new control

If you run 0.1.0 or 0.1.1, the first item is the reason to upgrade.

sh -c 'rm -rf /' was ALLOWED, and it was one of 44

The bare command was correctly refused throughout. Wrapping it was enough to turn the rule off:
sh -c, env sh -c, timeout 5 sh -c, nohup, setsid, xargs, find -exec, ssh host '…',
perl -e, node -e, eval — 44 of 55 wrapped forms allowed on the published 0.1.1, measured
against the tarball downloaded from the registry rather than a local build.

A rule marked outsideRepoOnly is skipped when every filesystem-looking argument resolves inside
allowed_paths. The tokenizer strips quotes, so -c 'rm -rf /' arrived as one token, rm -rf /,
which resolved relative to the repository into <repo>/rm -rf / — a path inside the allowed
scope. Everything looked in-scope, so the recursive-delete rule was never evaluated.

It needs no adversarial agent. Counted against 8,487 real agent shell commands: python3 -c
339, env 182, bash -c 89, node -e 50, xargs 26, timeout 17 — 8.1% of everything an
agent ran
arrives in one of these shapes as ordinary idiom.

Fixed with two independent fences: the effective program is resolved past runner prefixes, and any
argument token containing whitespace is refused classification. 0 of 55 wrapped forms escape
now
, with no change to precision or coverage on the frozen 92-block label set. One measured
false positive is named in the changelog rather than left to be found.

usewarden now watches its own policy

Every check watched the agents' hook registrations. None watched the rules those hooks enforce —
so a policy narrowed from the shell was enforced silently while status said PROTECTED and
doctor passed every row.

Preventing that write is not achievable from a hook, and README.md has always said so. Noticing
it is. The policy is now sealed at usewarden init — a verbatim copy, not a hash, because a
hash cannot be replayed — and status, doctor, the status line and usewarden policy --drift
report when the rules in force would catch less than the rules you installed. It compares
verdicts, not text: both rulesets run against a derived probe set and against your own recorded
incidents. A policy made stricter raises nothing, and usewarden reseal accepts a change you
meant.

Three findings are kept apart: catches lost, protections lost, and protections downgraded from
absolute (forbidden_paths, everywhere) to conditional (allowed_paths, only where you are
standing). The third is the one a block-count misses.

Also

  • usewarden reseal and usewarden policy --drift are new; usewarden replay shipped and was
    never documented.
  • SECURITY.md gains a known issues in published versions table naming both defects against
    0.1.0 and 0.1.1, so nobody has to read release notes to learn their version does not do what its
    page says.
  • The published repository's own npm test was broken in four ways that only a checkout of this
    repo could see. Found by building and testing the tree being pushed rather than the tree the
    checkout was standing in.

Full detail in CHANGELOG.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01To6RJknDDPxY3nihw4t64k

Stop your AI coding agent before it touches something it shouldn't. A local
guardrail for Claude Code, Cursor, Gemini CLI and more: it blocks out-of-scope
writes, .env reads, rm -rf and force pushes, with no API key and zero tokens.

It is not a firewall and not a sandbox. It intercepts what an agent DECLARES it
is about to do, through that agent's own hook system, and does not sit in the
kernel. An adversarial read of the earlier wording found that claim the first
thing to attack and the first thing to lose (DECISIONS.md D-095).

This is a single-commit history by design. The tool was built over eleven
verified phases in a private repository whose commits contain the build
machine's absolute paths and internal notes; publishing a rewritten version of
that history would leave the original blobs fetchable by SHA. The engineering
record it would have carried is published instead as DECISIONS.md and the
artifacts under verification/, both of which are checked by
scripts/pre-public-scan.sh before every push.
@djayamah
djayamah merged commit d7795f4 into main Sep 8, 2026
5 checks passed
@djayamah
djayamah deleted the release-0.1.2 branch September 8, 2026 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant