Two guarded-mode false-positives surfaced in real scan traces.
The reviewer blocked a boolean SQL injection probe
(`curl "…/login?username='+OR+'1'='1"`) for being an injection attempt at all,
though it is a read-only GET that changes nothing. The prompt said "allow only
non-destructive" but never established that in-scope offensive testing is the
tool's authorized purpose, so the model blocked on the technique. Rewrite the
guarded-mode guidance to judge by effect: in-scope injection probes, recon,
enumeration, and fuzzing pass, while destructive or persistent effects block —
with SQL spelled out (boolean/UNION/time-based read probes pass; DROP, DELETE,
INSERT, INTO OUTFILE, stacked statements, and command execution block).
Ambiguous evidence still fails closed, and every deterministic block, the
completeness gate, observe's passive-only rule, and scope enforcement are kept.
Separately the reviewer blocked a plain `curl` as "use of bash shell within a
curl command". The shell wrapper stamps `shell: bash` onto every exec_command
for execution, and the evidence packet passed that transport default straight
to the reviewer, which read it as the agent invoking a shell. Strip the
harness-injected transport keys (`shell`, `max_output_tokens`) from the packet's
original_arguments; the command itself is still parsed from `cmd`, so an
agent-authored `bash -c` payload is unaffected.
Note: the effect-based prompt also lets in-scope recon tools (nmap, subfinder,
ffuf, katana) through, which the old prompt blocked as "scanning" or "high
volume". That follows directly from judging by effect rather than technique.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The `agent_browser` skill is always loaded, so its safety paragraph shipped to
`off`-mode agents. Its prohibitions do not hold there — Strix only assigns a
browser session in a safety mode, while multi-session browsing is a normal
documented workflow — so the paragraph misdescribed the tools those agents
have. Move it into the already mode-gated block in the system prompt, and pin
the gating in both directions.
Test changes:
- `test_observe_mode_blocks_browser_click` asserted nothing about observe mode.
The same call blocks in guarded for a different reason (no prior snapshot),
so the observe rule was never reached. Give it a snapshot and assert the
block's source and category, plus the passive-read inverse.
- Neither workspace-epoch bump was pinned; removing either left the suite
green. Both are now covered, along with the read-only case that must not
bump, and an end-to-end pairing where a patch during review invalidates a
script decision.
- Cover `invoke_mutating_tool`'s observe-block and off-mode paths, the
reviewer's low-confidence, block, missing-model and failed-inspection rules,
the inline `bash -c` source path, and the two dependency-budget guards.
- Assert browser sessions are disjoint across agents rather than freezing one
agent's command string.
- Fold the compound-separator and safety-config tests into the parametrized
cases that already covered them.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Introduce a pre-execution safety layer that reviews effectful agent actions
against compiled, frozen evidence before they run.
`--safety-mode guarded` allows non-destructive interaction after review;
`--safety-mode observe` permits passive target interaction only. `off` stays
the default, so existing runs are unchanged.
Deterministic rules decide what they can on their own: destructive commands,
code-loading environment overrides, blocked browser actions, and mutating
requests in observe mode are refused without a model call, and a small set of
read-only commands is allowed outright. Everything else compiles an evidence
packet — command, scope, script source and its local import closure, prior
tool-call evidence, and browser snapshot context — for a bounded reviewer that
may make one isolated inspection call. Incomplete evidence fails closed.
In safety modes, user-owned local directories are copied into the run
directory so the originals are never mounted writable, while `.git`,
`.agents`, and `.codex` inside the copy stay read-only.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>