Skip to content

feat(agent-guard): refuse vetted operations spelled without the literal ~ - #1674

Open
potiuk wants to merge 3 commits into
apache:mainfrom
potiuk:feat/vetted-ops-tilde-guard
Open

potiuk wants to merge 3 commits into
apache:mainfrom
potiuk:feat/vetted-ops-tilde-guard

Conversation

@potiuk

@potiuk potiuk commented Oct 16, 2026

Copy link
Copy Markdown
Member

Summary

  • Why. The sandbox exclusions and permission rules name only the literal ~/.claude/magpie/<tool> spelling of the vetted dispatchers. An agent that expanded ~ to its home directory ran the read inside the sandbox, where gh fails TLS (OSStatus -26276), and the natural next steps were a sandbox bypass or the checkout copy uv run --project tools/vetted-ops …, which runs code the agent can edit.

  • Guard. A new bundled agent-guard guard, vetted-ops-spelling, refuses a uv run --project / uvx --from launch of vetted-op, vetted-op-read, vetted-op-tracker or adversarial-review when the base is:

    • the stable path spelled any other way (/Users/<you>/…, /home/<you>/…, $HOME/…, or the wrong dispatcher's link);
    • a relative checkout path (tools/vetted-ops, ./…, plugins/…).

    The refusal names the exact ~ command to run. Override: MAGPIE_ALLOW_VETTED_PATH=1 (developing the dispatcher itself).

    • Another harness's own installed plugin directory (absolute or ~/…/plugins/cache/…) is left to that harness's rules.
    • Codex keeps expanding ~ on the fly: its existing codex-expand-stable-path hook rewrites a lone vetted-op-read to the absolute stable path, and the guard lets exactly that path through when the Codex adapter calls it. dispatch() gains a narrow harness argument for this; only the Codex adapter sets it. Writes are still not rewritten, so they keep prompting.
    • uv / uvx are checked before the gh / git fast path; contributed guards still run on gh / git only.
  • Golden rule. AGENTS.md → Local setup states it.

  • Docs use only the ~ form.

    • secure-agent-setup, the vetted-ops README (both copies), the vetted-command-surface spec and setup-isolated-setup-install / -update / -verify drop the per-machine absolute-$HOME allow rules and exclusions. They are no longer needed once the guard redirects that spelling.
    • verify / update report a leftover absolute rule for removal; a copy in committed settings stays ✗.
    • The adversarial-review usage shows ~/.claude/magpie/adversarial-review instead of <plugin>/….
    • sandbox-lint keeps matching ask rules against both bases (an agent without the guard may still produce the absolute form); only its comments change.

Type of change

  • Skill change (setup-isolated-setup-install, -update, -verify)
  • Tool / bridge contract (tools/agent-guard guard set)
  • Python package (tools/agent-guard engine + plugin copy, tools/sandbox-lint comments)
  • Groovy reference impl
  • Cross-cutting (AGENTS.md golden rule, sandbox shape)
  • Documentation
  • Project template
  • CI / dev loop

Test plan

  • prek run --all-files passes
  • tools/agent-guard tests: allowed spellings, denied spellings, the named fix, the override, the Codex absolute-path exception (and that any other absolute path is still denied under Codex), plus the Codex adapter test now asserting harness="codex"
  • Eval suites for the three setup skills — not run here (the steps change from four allow forms to two; no existing fixture pins the absolute pair)

Notes for reviewers

  • The guard is on wherever agent-guard is installed; Step V.1 of the install skill now requires the plugin.
  • The dated design record docs/designs/2026-09-23-adversarial-review.md keeps its <plugin>/… wording as history.

Gen-AI disclosure: prepared with the assistance of Claude Code (Claude Opus 5); reviewed by the author.

🤖 Generated with Claude Code

…al ~

The sandbox exclusions and permission rules name only the
~/.claude/magpie/<tool> spelling of the vetted dispatchers. An agent
that expanded ~ to its home directory ran the read inside the sandbox,
where gh cannot verify TLS, and then reached for a sandbox bypass or a
checkout copy of the dispatcher, which runs code the agent can edit.

- A new bundled agent-guard guard, vetted-ops-spelling, refuses a
  uv run --project / uvx --from launch of vetted-op, vetted-op-read,
  vetted-op-tracker or adversarial-review from an expanded home path,
  $HOME/..., or a relative checkout path, and names the ~ command.
  Another harness's own plugin directory is left alone, and under Codex
  the absolute stable path its rewrite hook substitutes is let through.
  Override: MAGPIE_ALLOW_VETTED_PATH=1.
- AGENTS.md states it as a golden rule.
- The setup skills, secure-agent-setup and the vetted-ops README drop
  the per-machine absolute-$HOME allow rules and exclusions: the ~ form
  is the only spelling documented, and verify/update now report a
  leftover absolute rule for removal. The adversarial-review usage shows
  the ~ path instead of <plugin>/.

Generated-by: Claude Opus 5
@github-actions github-actions Bot added family:setup setup-* skills family:tools tools/* family:docs Docs, MISSION.md, READMEs capability:platform Framework / agent substrate skills (install, verify, doctor, override, status, setup bootstrap) substrate:sandbox Tool substrate: agent isolation, egress control, settings audit substrate:action-guard Tool substrate: deterministic pre-tool-use command guards substrate:review Tool substrate: second-model read of a change before publishing (read-only CLIs, merged findings) labels Oct 16, 2026
Comment on lines +652 to +653
"uvx --from ~/.claude/plugins/cache/apache-magpie/magpie-adversarial-review/0.9.0/tools/adversarial-review"
" adversarial-review detect",
- uv options on either side of `run` are read, so
  `uv --project tools/vetted-ops run vetted-op-read` is refused like
  `uv run --project tools/vetted-ops vetted-op-read`.
- An absolute path inside the working tree is refused as a checkout the
  agent can edit, like a relative one; an absolute path elsewhere is
  still a harness's own plugin directory.
- Under Codex, a vetted-op-read is let through from the exact root the
  rewrite hook is registered with (`--stable-path` in the Codex
  configuration, else the account's home), so a trusted `--tool-root`
  install keeps its rewritten reads. Any other root is one the agent
  could have built and stays refused, and so do writes, which the hook
  never rewrites.

Generated-by: Claude Opus 5

def _register_codex_hook(codex_home, root):
"""Write the hook registration `vetted-ops-codex-rules --hook --tool-root <root>` renders."""
import json
…config as TOML

- An absolute dispatcher path is checked for membership in a git working
  tree from the path itself as well as from the cwd, so launching from
  outside the repository (`uv --directory /repo run --project
  /repo/tools/vetted-ops ...`) is refused too. An installed plugin cache
  stays exempt even inside a version-controlled tree.
- The Codex hook registration is parsed with tomllib, so valid TOML such
  as an inline comment after the command no longer hides a registered
  `--stable-path` root.

Generated-by: Claude Opus 5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

capability:platform Framework / agent substrate skills (install, verify, doctor, override, status, setup bootstrap) family:docs Docs, MISSION.md, READMEs family:setup setup-* skills family:tools tools/* substrate:action-guard Tool substrate: deterministic pre-tool-use command guards substrate:review Tool substrate: second-model read of a change before publishing (read-only CLIs, merged findings) substrate:sandbox Tool substrate: agent isolation, egress control, settings audit

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants