Security3 of 10
Dangerous commands
On this page
A command that matches one of fourteen patterns is labelled dangerous. Nothing about it is automatic: it never auto-runs, no saved grant of either kind covers it, and neither "always allow" key appears on its card. It asks every time.
Say plainly what this is: a denylist of fourteen regular expressions read over the text of the command line. It is not a capability model and it is not a simulation of what the command would do. It catches the shapes it names.
The fourteen labels
Read out of core/approval.py. The label is what the card says the command is.
| Label | The shape it matches |
|---|---|
recursive-delete | rm with any recursive flag, rd/rmdir /s, Remove-Item -Recurse |
delete-root-or-home | a delete whose last argument is /, ~, /*, $HOME, a drive root or %USERPROFILE% |
privilege-escalation | sudo, su, doas, Start-Process -Verb RunAs |
pipe-to-shell | a download piped into a shell or into Invoke-Expression |
raw-disk-write | dd … of=, or a redirect into a raw disk device |
filesystem-format | mkfs, fdisk, mke2fs, format <drive>, diskpart, bcdedit, Format-Volume |
fork-bomb | the classic self-referencing function |
recursive-chmod-root | chmod -R applied to / or ~ |
power-control | shutdown, reboot, halt, poweroff, init 0, Stop-Computer, Restart-Computer |
history-or-key-wipe | a redirect that truncates shell history, ~/.ssh/ or ~/.aws/ |
destructive-find | find with -delete, -exec or -execdir |
file-truncate-shred | shred, truncate, or tee redirected to an absolute path |
registry-delete | reg delete, Remove-ItemProperty |
backup-wipe | vssadmin/wbadmin delete, cipher /w |
Four of them exist only for Windows, where the same harm wears different names and the card could not otherwise say what the command was.
recursive-delete asks only for a recursive flag, in any spelling or bundle. Requiring -f as well
would read a recursive delete of a home directory as ordinary, because -f only silences prompts
while -r is the flag that empties the tree.
destructive-find is on the list because find is one of the 29 auto-safe read commands. Without it,
a bare find . -delete would have run in the working folder with no card.
What is refused outright, and what merely asks
Nothing on this list is refused outright when there is someone to ask. The label changes what the card says and removes both "always allow" keys. You can still approve it, and it will run.
The one case where a dangerous label becomes a refusal is when no approval channel exists — a
sessionless or scripted call with no gate wired. There, shell refuses a labelled command rather
than running it unattended, and answers in plain language rather than with an error.
Under KOTOBA_SANDBOX=docker, where ordinary commands run without a card, a dangerous label is still
stopped and still asked. Measured: with the docker backend selected, rm notes.txt and npm install
run unasked, while sudo apt update, shutdown now, a download piped into a shell, and a redirect to
a raw disk device all raise a card.
What a denylist over shell text implies
Three things, and they are worth stating rather than leaving to inference.
It matches text, not behaviour. A command that reaches the same outcome by a spelling the list does not name is not labelled. The list is not a claim to have enumerated destruction.
The label is not the safety. What makes the default setting defensible is not this list — it is
that on KOTOBA_SANDBOX=local, everything that is not a plain read inside the working folder asks
anyway, unless you saved a grant for it. The dangerous list adds two things on top: it removes the
ability to save a grant at all, and it gives the card an honest word for what it is looking at.
It is the last line under docker, and it is a thin one. With the docker backend, ordinary
commands run without a card and the container is the boundary. If you are relying on this list to
catch things there, you are relying on a denylist over text. The container is what is actually
protecting you.
Where it sits relative to the rest
command
├── matches a dangerous pattern? → always a card, no grant can be saved
├── on the allow-list? → runs (empty in the running system)
├── covered by a saved grant? → runs
├── a plain read inside the jail? → runs
└── otherwise → a card
The Python path has its own list of seven patterns, over source rather than shell text. It works the same way and has the same limits: see execute_code.
