mirror of
https://github.com/usestrix/strix.git
synced 2026-08-25 04:12:37 +02:00
feat(safety): add contextual action review with guarded and observe modes
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>
This commit is contained in:
@@ -74,6 +74,55 @@ affecting the agents that do the actual testing.
|
||||
baseline when unset.
|
||||
</ParamField>
|
||||
|
||||
## Safety Review
|
||||
|
||||
<ParamField path="STRIX_SAFETY_MODE" default="off" type="string">
|
||||
Default action policy. Valid values: `off`, `guarded`, and `observe`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="STRIX_SAFETY_MODEL" type="string">
|
||||
Optional model used for contextual action review. Falls back to `STRIX_LLM`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="STRIX_SAFETY_REASONING_EFFORT" default="low" type="string">
|
||||
Reasoning effort for the safety reviewer.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="STRIX_SAFETY_TIMEOUT" default="60" type="integer">
|
||||
Timeout for one model request in a safety review. A review makes at most two
|
||||
requests, so the wall-clock budget is twice this value plus the inspection
|
||||
timeout.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="STRIX_SAFETY_MAX_OUTPUT_TOKENS" default="8192" type="integer">
|
||||
Output-token budget for one safety review turn. On a reasoning model this
|
||||
covers reasoning tokens as well as the verdict; too small a value truncates
|
||||
the decision and fails closed.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="STRIX_SAFETY_MAX_ARTIFACT_BYTES" default="262144" type="integer">
|
||||
Per-file limit for inspected script and dependency source.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="STRIX_SAFETY_MAX_TOTAL_ARTIFACT_BYTES" default="4194304" type="integer">
|
||||
Combined limit for one script's whole inspected dependency closure.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="STRIX_SAFETY_MAX_DEPENDENCIES" default="32" type="integer">
|
||||
Maximum local modules collected for one script entrypoint.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="STRIX_SAFETY_INSPECTION_TIMEOUT" default="5" type="integer">
|
||||
Wall-clock limit for the reviewer's optional isolated inspection script.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="STRIX_SAFETY_INSPECTION_IMAGE" type="string">
|
||||
Optional Docker image for isolated inspection scripts. Defaults to the scan
|
||||
sandbox image. The image must provide Python 3 and a `pentester` user.
|
||||
</ParamField>
|
||||
|
||||
See [Safety Modes](/usage/safety-modes) for behavior and limitations.
|
||||
|
||||
## Optional Features
|
||||
|
||||
<ParamField path="PERPLEXITY_API_KEY" type="string">
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"pages": [
|
||||
"usage/cli",
|
||||
"usage/scan-modes",
|
||||
"usage/safety-modes",
|
||||
"usage/instructions"
|
||||
]
|
||||
},
|
||||
|
||||
+8
-1
@@ -17,7 +17,7 @@ strix (--target <target> | --target-list <path>) [options]
|
||||
When the target is an API spec, Strix copies it into the agent's workspace and authorizes the base URLs it declares (including those resolved from a Postman environment) as in-scope hosts - so the agent reads the contract and tests the full declared surface instead of discovering endpoints by crawling. Pair the spec with the deployed base URL (e.g. `--target ./openapi.yaml --target https://api.example.com`) so the agent has a reachable host to attack.
|
||||
|
||||
<Note>
|
||||
A local directory is mounted into the sandbox live and **writable**, so the agent edits your real files (`.git` excepted). Commit or stash first.
|
||||
With safety mode `off`, a local directory is mounted into the sandbox live and **writable**, so the agent edits your real files (`.git` excepted). `guarded` and `observe` use a writable isolated copy instead.
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
@@ -41,6 +41,13 @@ strix (--target <target> | --target-list <path>) [options]
|
||||
Scan depth: `quick`, `standard`, or `deep`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="--safety-mode" type="string" default="off">
|
||||
Action policy: `off`, `guarded`, or `observe`. Guarded mode contextually
|
||||
reviews ambiguous actions and blocks destructive or persistent effects.
|
||||
Observe mode permits passive target interaction only. See
|
||||
[Safety Modes](/usage/safety-modes).
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="--scope-mode" type="string" default="auto">
|
||||
Code scope mode: `auto` (enable PR diff-scope in CI/headless runs), `diff` (force changed-files scope), or `full` (disable diff-scope).
|
||||
</ParamField>
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
---
|
||||
title: "Safety Modes"
|
||||
description: "Control state-changing actions during a scan"
|
||||
---
|
||||
|
||||
Safety mode is independent of scan depth. `quick`, `standard`, and `deep`
|
||||
control coverage; safety mode controls which effects may be executed.
|
||||
|
||||
```bash
|
||||
strix --target https://example.test --safety-mode guarded
|
||||
```
|
||||
|
||||
## Modes
|
||||
|
||||
| Mode | Behavior |
|
||||
| --- | --- |
|
||||
| `off` | Current autonomous behavior. Local directories are mounted live and writable. |
|
||||
| `guarded` | Allows non-destructive interaction after contextual review. Persistent or destructive target actions are blocked. |
|
||||
| `observe` | Passive target interaction only. Form submission, authentication, uploads, mutating requests, and state-changing controls are blocked. |
|
||||
|
||||
`off` is the default for backward compatibility. Configure a default with
|
||||
`STRIX_SAFETY_MODE` or select a mode for one run with `--safety-mode`.
|
||||
|
||||
## Contextual Review
|
||||
|
||||
Before an ambiguous shell or browser action executes, Strix compiles a frozen
|
||||
evidence packet containing the effective command, target scope, relevant script
|
||||
source and imports, prior tool-call evidence, browser snapshot context, and
|
||||
workspace persistence details.
|
||||
|
||||
The safety model may decide immediately or make exactly one `run_inspection`
|
||||
tool call. That call runs a Python standard-library analysis script in a
|
||||
separate networkless, read-only container over the frozen evidence. If the tool
|
||||
is used, the model's next response must be the final decision.
|
||||
|
||||
The review is bounded to at most two model turns and one optional inspection
|
||||
call. Timeouts, malformed decisions, a second tool call, incomplete evidence,
|
||||
or low-confidence approval fail closed.
|
||||
|
||||
## Deterministic Rules
|
||||
|
||||
Some outcomes never reach the model. Destructive commands, environment
|
||||
overrides that change which code an interpreter loads (`PYTHONPATH`,
|
||||
`LD_PRELOAD`, `AGENT_BROWSER_SESSION`, and similar), blocked browser actions,
|
||||
and mutating requests in `observe` mode are refused outright. A small set of
|
||||
read-only commands is allowed outright, but only when its options are also
|
||||
read-only: `rg --pre` and anything else that hands the command another program
|
||||
to run goes to review instead.
|
||||
|
||||
Commands that wrap another program (`sudo`, `timeout`, `xargs`, `nohup`, and
|
||||
similar) and interactive `write_stdin` payloads cannot be resolved to a single
|
||||
effective action before dispatch, so they are blocked. Issue the command as its
|
||||
own `exec_command` call.
|
||||
|
||||
## Scripts
|
||||
|
||||
When a command executes a script, Strix reads the current entrypoint and local
|
||||
Python imports without importing or running them. Inline `python -c` source is
|
||||
analyzed the same way. Absolute imports resolve against the entrypoint's
|
||||
directory and relative imports against the importing module's package, so the
|
||||
whole local closure is inspected. Decisions bind to content hashes. Dynamic
|
||||
code execution, import-path mutation, unresolved generated commands, oversized
|
||||
dependency closures, entrypoints outside `/workspace`, and unsupported evidence
|
||||
block the action.
|
||||
|
||||
Browser automation inside scripts is blocked in safety modes. Issue browser
|
||||
operations as individual raw `agent-browser` commands so each action can be
|
||||
reviewed against the current snapshot and element references.
|
||||
|
||||
Commands that create and execute code in one shell expression should be split
|
||||
into separate creation and execution calls.
|
||||
|
||||
## Browser Commands
|
||||
|
||||
Strix continues to use the raw `agent-browser` CLI. In safety modes it assigns
|
||||
an isolated browser session per agent and rejects model-supplied session,
|
||||
profile, or CDP overrides.
|
||||
|
||||
Interactions with element references require a prior recorded snapshot. A
|
||||
snapshot taken before a navigation or any other page-changing action is stale:
|
||||
the action is blocked and the agent must snapshot again.
|
||||
|
||||
Composite operations such as `auth login`, arbitrary `eval`, browser state
|
||||
persistence, and uploads are blocked. Guarded login should use explicit fill
|
||||
and submit steps with credentials supplied in the initial user instruction.
|
||||
|
||||
## Workspace Isolation
|
||||
|
||||
For `guarded` and `observe`, user-owned local directories are copied into:
|
||||
|
||||
```text
|
||||
strix_runs/<run>/.state/workspaces/<name>
|
||||
```
|
||||
|
||||
The copy is mounted writable, while the original source remains unchanged.
|
||||
`.git`, `.agents`, and `.codex` inside the copy stay read-only: they carry
|
||||
repository and agent-instruction state that survives `--resume`. Copies are
|
||||
retained for resume. Repository targets are already cloned into a disposable
|
||||
location and do not need another copy.
|
||||
|
||||
In-tree symlinks are materialized. Dangling, cyclic, device, and out-of-tree
|
||||
symlinks are omitted. Files are copied rather than hard-linked.
|
||||
|
||||
## Limitations
|
||||
|
||||
Contextual review reduces accidental harmful actions; it is not a complete
|
||||
network containment boundary. Arbitrary dynamic programs, raw sockets, or
|
||||
processes that ignore proxy settings cannot always be predicted statically.
|
||||
Unresolvable behavior blocks in safety modes.
|
||||
|
||||
Deterministic rules cover the cases listed above. Every other command is judged
|
||||
by the safety model against compiled evidence, so a tool whose effects are not
|
||||
statically recognizable — a scanner or exploit framework that mutates the
|
||||
target through its own protocol, for example — rests on that judgment rather
|
||||
than on a rule. Strong containment additionally requires externally enforced
|
||||
egress policy and reduced sandbox privileges.
|
||||
Reference in New Issue
Block a user