Skip to content

fix(agent-guard): unwrap env/command prefixes and refuse a quoted ~ - #1690

Closed
liwenjie200543 wants to merge 1 commit into
apache:mainfrom
liwenjie200543:fix/agent-guard-prefix-wrappers-quoted-tilde
Closed

liwenjie200543 wants to merge 1 commit into
apache:mainfrom
liwenjie200543:fix/agent-guard-prefix-wrappers-quoted-tilde

Conversation

@liwenjie200543

Copy link
Copy Markdown
Contributor

Fixes #1679.

The engine now unwraps env / command prefixes before any guard runs:
env with its options (-i, -u NAME in both spellings, --unset=NAME,
--) and its NAME=value assignments — which still feed Segment.env,
so env MAGPIE_ALLOW_VETTED_PATH=1 … keeps working — and command with
-p / --. Nesting unwraps too (env command git …), and command -v,
which locates rather than runs, ends the wrapper instead of fabricating a
bare argv; the "prefix wrappers remain a separate gap" note in
Segment.__init__ is gone with the gap.

For the quoted ~, split_segments now pairs every token with its own
source text (Segment.raw_argv) and _vetted_launch reports the argv
slot the base arrived in, so vetted-ops-spelling reads the spelling, not
just the value: a quoted or backslash-escaped ~ that parses to the
stable path is refused with the same corrected-command message — the
shell never expands it, so uv receives a directory literally named ~
and the sandbox exclusion does not match.

Verification: pytest 332 passed in tools/agent-guard (the 73 baseline
failures are an artifact of this working copy carrying only
tools/agent-guard, so the skill-owned guards fail discovery — CI's full
checkout does not see them); ruff check + format clean; mypy clean apart
from the two pre-existing Windows pwd/getuid notes.

The engine looked only at a segment's first word, so `env git commit`
and `command git push` slipped past every guard, and vetted-ops-spelling
compared the base after shlex removed the quotes, so a quoted `~` -
which the shell never expands - matched the allowed spelling.

Unwrap `env` (options -i, -u NAME in both spellings, --unset=NAME, --,
and NAME=value assignments, which still feed Segment.env so overrides
keep working) and `command` (-p, --) in the engine, before any guard
runs; nesting unwraps too, and `command -v` - which locates rather than
runs - ends the wrapper instead of fabricating a bare argv.
split_segments now pairs every token with its own source text
(Segment.raw_argv), so vetted-ops-spelling can read the spelling: a
quoted or escaped `~` that parses to the stable path is refused with
the same corrected-command message.

Tests cover every wrapper form per guard family, the override behind
`env` assignments, and each spelling the shell will not expand.
@github-actions github-actions Bot added family:tools tools/* substrate:action-guard Tool substrate: deterministic pre-tool-use command guards labels Oct 17, 2026
@potiuk

potiuk commented Oct 17, 2026

Copy link
Copy Markdown
Member

Thank you for working on this, and for the careful write-up. #1679 was fixed by #1691, which merged yesterday and covers the same ground: unwrapping env / command prefixes and refusing a quoted ~ in vetted-ops-spelling. Since this PR now conflicts with that change and has no remaining gap to close, I'm closing it as superseded. If you spot a case #1691 still misses, a new issue or PR against current main would be very welcome.


Drafted-by: Claude Code (Opus 5); reviewed by @potiuk before posting

@potiuk potiuk closed this Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

family:tools tools/* substrate:action-guard Tool substrate: deterministic pre-tool-use command guards

Projects

None yet

Development

Successfully merging this pull request may close these issues.

agent-guard: env/command prefixes and a quoted ~ slip past vetted-ops-spelling

2 participants