Running Shell Commands With a CLI Agent Safely
The scary part of cli agent shell commands isn't the obviously destructive command — it's the plausible one with a wrong flag, approved on autopilot. Here's how to allowlist by pattern, deny the catastrophic, and sandbox the rest.
# The overloaded setup: full shell, no gate claude --permission-mode bypassPermissions # or the Aider equivalent of just saying yes to every /run
Here's the counterintuitive part about letting an agent run your terminal: the dangerous command is almost never the one that looks dangerous. Nobody approves
rm -rf /git push --forcepsqlOnce you understand that, the whole approach to shell access changes. Let's tear down the weak way people set this up and build the version that's actually safe.
Before: The Weak Way to Approve Commands
The default instinct is blanket approval. You get tired of confirming every command, so you flip the switch that says "stop asking."
[object Object],
claude --permission-mode bypassPermissions
,[object Object],What this does: Runs the agent with permission checks off, so it executes any shell command without a prompt. It feels productive for about ten minutes — right up until the agent runs something you'd never have approved if you'd read it.
The problem isn't that the agent is malicious. It's that an agent optimizing to complete a task will reach for whatever command gets there, and "get there" and "safe" aren't the same goal. Ask it to "clean up the branches" and it may cheerfully delete a branch you hadn't merged. It did exactly what you said. That's the whole problem.
⚠️ Common mistake: Treating bypass mode as a time-saver. It trades a two-second confirmation for an unbounded downside. The correct trade isn't "approve everything" versus "approve nothing" — it's approving categories of command once, so the routine stuff flows and the dangerous stuff still stops.
Why It Fails: Approval Fatigue Is the Attack Surface
Blanket approval fails for a human reason, not a technical one. When every command needs a yes, you stop reading them. By the fiftieth
npm testThis is why "just review each command" doesn't scale as a safety strategy. Humans are bad at staying vigilant across dozens of near-identical decisions. Any system for cli agent shell commands that depends on you carefully reading every single one will fail exactly when it matters, because that's when you're deepest in the reflex.
The fix is to move the decision from runtime to setup time. Decide once, when you're thinking clearly, which categories of command are always fine, which always need a look, and which are simply forbidden. Then the agent runs freely inside the safe set and only interrupts you for the genuinely consequential calls.
After: Allowlist by Pattern, Not by Blanket
The strong setup grants specific command patterns instead of all-or-nothing access. Claude Code supports scoped tool rules that match shell commands by shape, so you can say "read-only git is always fine" without opening the door to everything.
claude --allowed-tools ,[object Object], ,[object Object], ,[object Object], ,[object Object], ,[object Object],What this does: Lets the agent read files, search, run
git diffThe mirror image is the denylist, and it's the more important half. Some commands should never run unattended regardless of context.
[object Object],
{
,[object Object],: {
,[object Object],: [,[object Object],, ,[object Object],, ,[object Object],]
}
}What this does: Refuses force-pushes, recursive deletes, and anything mentioning
prod⚡ Pro tip: Write your deny list from real incidents, not imagination. The first time an agent does something you had to undo, add that command shape to the deny rules. Within a few weeks your denylist encodes your team's actual scar tissue, which is far more accurate than a generic list you copied from a blog.
Breaking Down Each Element of Safe CLI Agent Shell Commands
Four pieces make shell access safe, and they compose.
The allowlist handles routine throughput. Read-only inspection, tests, formatters,
git diffThe denylist handles the catastrophic set. Force pushes, destructive deletes, anything touching production. These never run without you, full stop.
The sandbox handles the unknown middle. Cursor's CLI ships a network-denied-by-default sandbox configured through
sandbox.json[object Object],
cursor-agent -p ,[object Object], --mode planWhat this does: Runs the agent in read-only plan mode first, so it tells you which commands it intends to run before any of them execute. Combined with the sandbox, an unexpected command is contained even if you approve it by reflex.
The turn limit handles runaway loops. A
--max-turnsclaude -p ,[object Object], --permission-mode dontAsk --max-turns 5What this does: Runs a bounded, non-interactive session that pre-approves the allowlisted tools but stops after five turns. For unattended automation,
dontAskThe Command Category Everyone Forgets: Network Calls
Ask people to name dangerous commands and they list file deletions and force pushes. Almost nobody names
curlwgetpip installnpm installThis is exactly why the network-denied-by-default sandboxes matter more than they first appear. When an agent can't reach the network unless you explicitly allow it, a task that only needed to edit files and run tests simply can't phone home, no matter what command it constructs.
[object Object],
{
,[object Object],: {
,[object Object],: [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],]
}
}What this does: Blocks the agent from making network calls or installing packages without an explicit exception. Most coding tasks never need these, so denying them by default costs you nothing and closes the quietest hole in your setup.
The nuance is that some tasks legitimately need a package installed. The right move isn't to permanently allow installs — it's to grant the exception for that one session, watch what it installs, and revoke it after. Standing network access for a coding agent is almost never justified.
⚡ Pro tip: Treat any agent request to install a package as a review checkpoint, not a rubber stamp. Ask which package and why, and pin the version. Agents will confidently reach for a package to solve a problem your existing dependencies already handle, adding supply-chain surface you didn't need.
⚡ Pro tip: Run agents that don't need the internet with the network off entirely. A refactor, a bug fix, a test-writing task — none of these need to reach out. Turning the network off for the whole session is the simplest, strongest version of the denylist, and it makes exfiltration impossible rather than merely disallowed.
Variations for Different Contexts
A DevOps engineer wiring an agent into CI: allowlist the read-only and test commands, deny everything that mutates infrastructure, and run headless with a strict turn cap. The pipeline agent can diagnose and propose, but a human merges the PR.
A data scientist running an agent against notebooks and datasets: deny any command matching the production database connection string, allowlist the local analysis tools, and keep network access off unless a specific task needs it. The agent can slice data all day and never phone home.
A backend developer doing local feature work: run interactively with a generous allowlist for the dev loop (
git diffA platform team supporting fifty engineers: put the allow and deny rules in a committed settings file and an enterprise-managed policy layer so the denylist can't be relaxed by an individual. The categories that must never run are enforced org-wide, not left to each person's discipline.
⚡ Pro tip: Scope your allowlist to the narrowest pattern that still flows.
Bash(git diff *)Bash(git *)git pushgit reset --hardSave and Reuse This
Safe cli agent shell commands come down to one shift: stop deciding at runtime and start deciding at setup. Allowlist the routine command patterns so throughput stays high, denylist the catastrophic ones so they never run unattended, sandbox the unknown middle so surprises stay contained, and cap turns so nothing spirals. Blanket approval isn't the fast path — it's the slow path with a delayed bill.
The allow rules, deny rules, and sandbox configs that work for your stack are the same across every repo you touch, so write them once and reuse them. Keeping those permission templates in PromptABCD means a new project inherits your hard-won guardrails on day one instead of relearning them the expensive way.
Continue Reading
Save the prompts from this post
PromptABCD is a free prompt manager. Paste, organize, and reuse your best AI prompts — no more hunting through chat history.
