# Destructive command rules

The six rules zn-gate can use to refuse a shell command that would wipe a machine or run a download unread: what each one blocks, how to turn them on or off, and what the check does not see.

Source: https://usezn.com/docs/zn-gate/destructive-commands/

zn-gate can refuse a small set of shell commands that wipe a machine or run a download unread. Two of the rules are **on by default** in the agent hooks: `rm_root_home` (a recursive delete of the home folder, the filesystem root or a system folder) and `disk_overwrite` (a write to a disk device). The other four rules (`pipe_to_shell`, `rc_download`, `perm_root`, `fork_bomb`) are **off by default** and you can turn them on. You can also turn the two default rules off.

This is a guardrail against a model's mistake or a bad suggestion, not a sandbox. It reads the text of one command and blocks it only when the command has one of the shapes below.

When a command is blocked, it does not run, and the agent is told why and to ask you to confirm before it runs the command. If you do want it, run it yourself in a terminal. Words you do not know are in the [glossary](https://usezn.com/docs/glossary/).

## Change the settings

For the agent hooks (the ones `zn hooks install` sets up for your agents), set `hooks.blockDestructiveCommands` in `~/.zn/config.json`:

| Setting | Rules applied |
| --- | --- |
| not set | `rm_root_home` and `disk_overwrite` (the default) |
| `true` | all six rules |
| `false` | none: the check is off |
| a list of rule names, for example `["rm_root_home", "pipe_to_shell"]` | exactly those rules (a name that is not a rule is ignored) |

```json
{"hooks": {"blockDestructiveCommands": false}}
```

The environment variable `ZN_BLOCK_DESTRUCTIVE=1` turns on all six rules. The environment can only add protection, never remove it: `ZN_BLOCK_DESTRUCTIVE=0`, any other value, or no value is ignored and leaves the file (or the default) in charge. A project an agent works in can set an environment variable, so turning rules off is only possible from the config file, which the agent's file tools cannot write.

When the check applies, the hooks run it on the shell tools of your agent (for example Bash and PowerShell).

In your own code, call the function directly. Calling it is the opt-in: it always applies all six rules.

- Node.js: `checkCommand(command)` from `zn-gate/lib/client`
- Python: `check_command(command)` from `zn_gate`

Both return the same kind of result as `evaluate`, with a rule such as `destructive:rm_root_home`. See the [SDK page](https://usezn.com/docs/zn-gate/sdk/). The settings above apply to the agent hooks only.

## What it blocks

| Rule | Default | Blocks | Examples |
| --- | --- | --- | --- |
| `rm_root_home` | on | A recursive delete of the home folder, the filesystem root, a top-level system folder or a drive root. Also `find` with `-delete` or `-exec rm` on those paths and no test such as `-name`. | `rm -rf ~`, `rm -rf /`, `rm -rf /usr`, `Remove-Item -Recurse -Force $env:USERPROFILE`, `rd /s /q C:\` |
| `pipe_to_shell` | off | A download that is run as a script without being read. | `curl https://example.com/install.sh \| sh`, `sh -c "$(curl ...)"`, `bash <(curl ...)`, `iwr ... \| iex` |
| `disk_overwrite` | on | `dd` with `of=` a block device, `mkfs`, `mkswap`, `wipefs`, `shred` or `blkdiscard` on one, a redirect into one, PowerShell `Format-Volume` and `Clear-Disk`. | `dd if=/dev/zero of=/dev/sda`, `mkfs.ext4 /dev/nvme0n1p2` |
| `perm_root` | off | `chmod -R`, `chown -R` or `chgrp -R` on the filesystem root or a top-level system folder; `chmod -R` with a world-writable mode on the home folder. | `chmod -R 777 /`, `chmod -R 777 ~` |
| `fork_bomb` | off | The classic shell fork bomb, under any function name. | a function that calls itself twice in the background |
| `rc_download` | off | A download written into a shell startup file (`.bashrc`, `.zshrc`, `.profile`, `/etc/profile`, fish `config.fish`). | `curl -o ~/.bashrc https://example.com/rc` |

"Top-level system folder" means `/bin`, `/boot`, `/dev`, `/etc`, `/home`, `/lib`, `/lib32`, `/lib64`, `/opt`, `/proc`, `/root`, `/sbin`, `/srv`, `/sys`, `/usr`, `/var`, and on macOS `/Users`, `/System`, `/Library`, `/Applications`, `/private`, `/Volumes`. A deeper path such as `/var/lib/apt/lists` or `/usr/local/lib/node_modules/x` is not blocked.

The command is split the way the rest of zn-gate's hook checks split it, so quotes, `&&`, `;`, pipes, `sudo`, `env`, `nohup` and similar wrappers are understood. The code of `sh -c`, `bash -lc`, `eval`, `pwsh -Command` and `cmd /c` is checked too, up to three levels deep. Text that only mentions a command inside quotes (`echo "rm -rf ~"`, a commit message) is not blocked.

## What it does not do

The check reads command text only. These are **not** covered, and the check lets them through:

- A path the command builds while it runs: `rm -rf "$DIR"` with an empty `DIR`, `rm -rf *` in an unknown folder, or a target that comes from a pipe.
- A script saved first and run later (`curl -o x.sh ... && sh x.sh`), or a download piped into a program that is not a shell (`curl ... | python3`).
- Other tools and languages (`rsync --delete`, `git clean`, a Python one-liner that deletes a folder), and paths below the top level (`rm -rf /usr/local`).
- Commands that run inside a container or on another machine.
- Anything an agent does by writing a file and then running it.

For those, use a sandbox, a container or your agent's own permission prompts. This check adds a cheap last barrier for the most common catastrophic mistakes.

## How well it works

The test set has about 1,000 ordinary developer commands (builds, git, package managers, containers, deleting `node_modules` or `dist`, `curl -o`, edits to `.bashrc`, and many that sit close to the blocked shapes) and about 550 commands with the blocked shapes, written from templates with varied flags, targets and fictitious hosts. On that set there are no false positives and no misses. The same people wrote the set and the rules, so read it as a regression test, not as an error rate on all real commands.

## If it blocks a command you want

Run the command yourself in a terminal. The check applies to agents only. If a rule gets in your way often, turn that rule (or the whole check) off with the settings above.
