11 min read

The Commands I Never Let an AI Agent Run (and How I Sandboxed OpenClaw)

Dharmik Jagodana

Someone on X asked a simple question the other day:

"What's one command you never let an AI agent run without asking you first?"

My answer took about five seconds:

Anything that deletes files or force pushes. And anything that touches the production database 😅

Short answer. The setup behind it is my AI agent security checklist.

I run a one-person company. Day to day, agents help me handle code, build features, set up deployments to Cloudflare, and run security checks. That only works because the dangerous stuff never runs without me.

I used to run OpenClaw. I don't anymore. The commands below stayed. The OpenClaw section is the setup I used, and the config I'd start with if I were locking it down again.

Below: the commands I never let an agent run alone, why each one is on the list, and how I enforced them.

Link to this sectionWhy a Deny-List Matters More Than a Smart Model

Agents don't have taste. They follow instructions.

I wrote about this in The Hidden Reality of Running a Business with AI Agents. Instructions miss edge cases. Small deviations compound. Most of the time that means a blog post that feels a little off.

But when the agent has a shell, "a little off" can mean a deleted folder. Or a rewritten Git history. Or a production table that's gone.

The model being smart doesn't change that. A good model with a bad instruction, or a prompt injection hidden in a web page it just read, will still run the command.

So I don't rely on the model to be careful.

I rely on the setup to make careless impossible.

My rule: if a mistake can't be undone in five minutes, the agent doesn't get to make it alone.

Link to this sectionThe Commands I Never Let an Agent Run Alone

Link to this section1. Anything That Deletes Files

rm -rf, find ... -delete, cleaning up "old" folders, wiping a build directory that turns out to hold something important.

Deleting is the fastest way for a helpful agent to do damage. It's also the hardest to notice. Nothing errors. Things are just... gone.

Link to this section2. Force Pushes and History Rewrites

git push --force, git reset --hard on shared branches, rebasing something that's already pushed.

A force push doesn't just change your code. It changes everyone's version of the truth. If an agent "fixes" a messy branch by rewriting history, the work it overwrote may not exist anywhere else.

Agents reach for --force because it makes errors go away. That's exactly the problem.

Link to this section3. Anything That Touches the Production Database

Migrations. DROP. DELETE without a WHERE. "Quick fixes" to a row. Even reads, if the data is sensitive.

The production database is where my users' data lives. An agent doesn't know which table is safe to experiment on. It doesn't know a migration will lock a busy table. It doesn't know that "test user" is actually a paying customer.

Prod is the one place where I want zero creativity.

Link to this section4. Anything That Reads or Moves Secrets

.env files, API keys, SSH keys, the ~/.openclaw directory itself.

In my OpenClaw security guide I wrote that I treat ~/.openclaw like my SSH keys. Same idea here. An agent that can read secrets can leak them, through a log, a commit, or a request to some URL it was tricked into calling.

Link to this section5. Anything That Sends or Publishes

Emails to users. Posts. Deploys. Anything a real person will see.

This one comes straight from how I place human checkpoints: high risk gets reviewed before execution, low risk gets reviewed after. Sending and publishing are high risk because you can't un-send an email.

Link to this sectionWhen I Ran OpenClaw

A list in a prompt is a suggestion. The agent can forget it, misread it, or get talked out of it.

When I ran OpenClaw, I wanted those rules outside the model. I did not keep the exact sandbox mode, workspace access, or allowlist. If you run OpenClaw, start here. These are the values I'd set. They are not a paste of my old file.

Link to this sectionLayer 1: Run Agents in a Sandbox

OpenClaw can run agent sessions inside containers instead of on your machine. Three settings control it: mode, scope, and backend.

Sandboxing does nothing until you turn it on. mode defaults to "off".

  • mode: "off": no sandboxing
  • mode: "non-main": sandbox every session except the agent's main session
  • mode: "all": sandbox everything

The Docker backend's defaults are already tight: no network (network: "none"), a read-only root filesystem, all Linux capabilities dropped (capDrop: ["ALL"]), and no-new-privileges. The default image is openclaw-sandbox:trixie-slim.

OpenClaw's config file is openclaw.json. This is the shape I'd start with:

json5
{
  agents: {
    defaults: {
      sandbox: {
        mode: "non-main",        // or "all" if no session should touch the host
        backend: "docker",
        scope: "session",        // each session gets its own container
        workspaceAccess: "ro",   // agent workspace read-only at /agent
        docker: {
          network: "none",       // no egress
          readOnlyRoot: true,
          capDrop: ["ALL"],
          tmpfs: ["/tmp", "/var/tmp", "/run"],
        },
      },
    },
  },
}

Why this matters: with mode set to non-main or all, an agent tricked into rm -rf is deleting files inside a throwaway container. Not on the host.

One thing in the docs I did not expect: denying the file tools does not make an agent read-only. exec is still a shell.

  • "ro" mounts the agent workspace read-only at /agent and turns off write, edit, and apply_patch.
  • "none" does not mount the agent workspace at all. The default.
  • "rw" mounts it read-write at /workspace.

"ro" is not a frozen container. The tmpfs paths (/tmp, /var/tmp, /run) stay writable, so a shell can still write there. If the agent should not write anything, deny exec too.

Link to this sectionLayer 2: Allowlist Commands, Ask on Everything Else

This is the part that turns the "never alone" list into something the process enforces.

OpenClaw has exec approvals, controlled by tools.exec.mode:

ModeWhat It Does
denyBlock host exec entirely
allowlistRun only allowlisted commands, no prompts
askRun allowlisted commands, ask me for anything else
autoRun allowlist matches, send misses to a reviewer that can allow once, deny, or ask a human
fullRun everything, no ordinary prompts

Here's the trick: my deny-list is really an allowlist.

I don't try to list every dangerous command. That's a losing game, because there are a hundred ways to delete a file. Instead I allow the boring, safe commands and let everything else hit an approval prompt.

json5
{
  tools: {
    exec: {
      mode: "ask",              // allowlist hits run, misses ask me
      strictInlineEval: true,   // python -c, node -e etc. always need approval
    },
  },
}

If no approval UI is reachable, askFallback defaults to deny. A missed prompt does not run the command.

There's also a built-in preset that sets most of this in one go: openclaw exec-policy preset cautious (allowlist, ask on miss, deny as fallback).

Watch out for this one: allowlisting git allows all of git, including git push --force. OpenClaw lets you add an argPattern (a JavaScript regex on the arguments) to an allowlist entry, so you can allow git status and git diff while git push --force still hits the prompt:

json
{
  "version": 1,
  "agents": {
    "main": {
      "allowlist": [
        { "pattern": "rg" },
        { "pattern": "git", "argPattern": "^(status|diff|log|show)( .*)?$" }
      ]
    }
  }
}

argPattern is checked against the arguments, not against the git token. Do not also add a path-only { "pattern": "git" }. A miss falls back to that entry, and git push --force would run.

This lives in the exec approvals policy. Set it with openclaw approvals, not by editing the file by hand. openclaw approvals get shows the effective policy. The git pattern above is an example of the shape. It is not an allowlist I kept.

Skip YOLO mode on anything that can reach real data. openclaw exec-policy preset yolo sets host exec to security full and ask off, and sets askFallback to full. That is the same end state as tools.exec.mode "full" plus host askFallback "full". Fine for a throwaway experiment. The opposite of this post.

Link to this sectionLayer 3: Least-Privilege Credentials

The sandbox protects the machine. Credentials decide what the agent can reach outside it.

Separate keys per agent or per project. Least privilege. No production keys on a machine an agent can read.

That is the rule I'd start with. It is not a claim about a specific key I issued.

Secrets live in files with tight permissions, as in the security guide: chmod 700 ~/.openclaw, and chmod 600 on openclaw.json and secret files.

Link to this sectionLayer 4: Production Lives Somewhere Else

The simplest way to stop an agent touching the production database is to make sure it can't see it.

  • Agents work against a local or staging database, never prod.
  • If it needs production data, give it a read-only user on a replica or a snapshot, not the primary.
  • A migration that touches production waits for approval. The agent can draft it. A person runs it.

Link to this sectionLayer 5: Git Protections That Don't Trust Anyone

Even if an agent somehow runs git push --force, the remote should say no.

  • Protect main with branch protection or rulesets: block force pushes, block deletion, require a pull request.
  • Agents work on their own branches and open PRs. They don't push to main.
  • CI runs on every PR, so broken changes get caught before I even look.

This is the layer that protects you from yourself too.

Link to this sectionLayer 6: Watch What They Do

Approvals and sandboxes stop the obvious stuff. Monitoring catches the weird stuff.

Monitor in production. Staging will not show you the weird cases. Agent behavior changes with real data. Track task success rates, cost drift, and quality over time.

For OpenClaw specifically:

  • openclaw logs --limit 100 for a quick look at what ran. --follow streams the log.
  • Look for unexpected command executions, sessions from unknown sources, and API usage spikes

This is also a big part of why I built AgentCenter: when you have a team of agents running, you need one place to see what each one is doing, what it delivered, and where it got stuck.

Link to this sectionWhat I use now

I moved off OpenClaw. The agents that help me now are Claude Code, Claude cloud agents, and Grok Bot.

The rules came with me. They work on a branch and open a pull request. Nothing pushes to main. A deploy, including one to Cloudflare, waits for me. So does anything that touches production or a secret.

Claude Code can write that down in .claude/settings.json. This example is from the Claude Code settings docs. It is not my file. permissions.allow lets a command run without a prompt. permissions.deny blocks one. Deny is checked first, so an allow rule cannot override it. The file is strict JSON. A comment or a trailing comma is a syntax error.

json
{
  "permissions": {
    "allow": ["Bash(npm run *)", "Bash(git diff *)"],
    "deny": ["Read(./.env)", "Read(./.env.*)"]
  }
}

A Read(./.env) deny blocks Claude Code's file tools on that path. It does not catch every shell command that reads a file without naming it. The docs say that. The rule helps. It is not a lock on the disk.

Grok Bot asks for approval before risky actions.

Claude's cloud agents get the same rule as the local ones. A branch, a pull request, and my approval before a deploy or anything on production.

Link to this sectionThe AI agent security checklist

Here's the whole thing in one place. The OpenClaw lines are where I'd start if I were setting it up again. The rest is what I still require: a branch, a pull request, and my approval before a deploy or anything that touches production or secrets.

Never without approval

  • File deletion (rm, find -delete, "cleanup" tasks)
  • git push --force, git reset --hard, history rewrites
  • Anything that connects to the production database
  • Reading, printing or moving secrets (.env, keys, ~/.openclaw)
  • Sending emails, publishing, deploying

Sandbox

  • agents.defaults.sandbox.mode set to non-main or all (the default is off)
  • Docker backend left on its defaults: network: "none", readOnlyRoot: true, capDrop: ["ALL"]
  • workspaceAccess: "ro" or "none" when the agent should not write the workspace ("rw" is the writable value)
  • exec denied when the agent should not write at all ("ro" still leaves tmpfs writable)

Exec approvals

  • tools.exec.mode: "ask" (or openclaw exec-policy preset cautious)
  • Allowlist only safe, boring commands
  • argPattern on git so pushes and resets still prompt
  • strictInlineEval: true
  • askFallback left as deny
  • No YOLO mode on anything that can reach real data

Credentials and prod

  • No production keys on a machine an agent can read
  • Separate keys per agent or project, least privilege
  • ~/.openclaw at 700, openclaw.json and secret files at 600
  • Agents use local or staging data; prod reads only through a read-only user
  • Migrations reviewed and run by a human

Git

  • Force pushes and branch deletion blocked on main
  • Agents work on branches and open PRs
  • CI on every PR

Monitoring

  • Logs checked regularly (openclaw logs --limit 100)
  • Cost and success rate tracked over time

Link to this sectionFinal thought

Agents are great at doing work. They're terrible at knowing which work is irreversible.

That's my job.

The setup above isn't about distrusting AI. It's the same thing I'd do for a new hire: give them a safe place to work, the access they need and nothing more, and a second pair of eyes on anything that can't be undone.

Delegate and supervise. Not set and forget.

If you're running OpenClaw on a server, start with the security guide and then come back to this checklist. And if you're curious how this fits into running a whole business with agents, read Building a One-Person Company with AI Agents.

What's on your "never without me" list? Tell me on X. I'm always collecting new ones.


I write about building real products with AI agents: setups, costs, and what breaks. One email when there's a new post, no fluff.

Subscribe.

You might also like

All posts