termique
Blog
Guide8 min read

AI coding agents over SSH: who approves the commands they run

AI agents that run commands on your servers need a control point. How command approval works, and the safety patterns that keep agents useful.

AI coding agents over SSH: who approves the commands they run

The workflow of running an AI agent on a remote server is becoming a normal part of operations: the agent reads the repo, proposes a fix, and runs a test or two against the live environment. The question that changes everything is who approves the commands it runs. An agent with unrestricted shell access to a server is a security boundary you built and then deleted.

Why unrestricted command execution is the real risk

A coding agent is not malicious, it is just confidently fallible. It will occasionally run the wrong command against the wrong host, or propose a fix with a destructive flag that makes sense in one context and is fatal in another. The danger is not intent, it is the absence of a confirmation step. A human who reads the exact command before it runs is the cheapest, most reliable guardrail there is.

The other half of the risk is scope. An agent logged in as root, or as a user that can reach every host, is one bad suggestion away from a fleet-wide incident. Both halves matter: what the agent can do, and who gets to rubber-stamp it.

The failure modes are familiar if you have seen a confident teammate in a terminal: the wrong environment variable, the target host behind the wrong jump, the restart that hits the staging box instead of production because the session context was ambiguous. An agent multiplies that speed without adding judgment, unless a human is explicitly in the loop on each command.

The approval pattern: propose, never auto-run

# the pattern in the weakest form
agent: run: systemctl restart nginx
human: approved?        -> yes / no
# the stronger form: the agent cannot execute at all
agent: propose: systemctl restart nginx
human: runs it manually, in the terminal they trust

The key property is that the agent proposes a command as text and the human triggers execution, ideally in the same session where they can see the host they are on. That keeps the “who approved which host” answer unambiguous.

The strongest form, the agent cannot execute at all, has a subtle advantage beyond safety: it keeps the human’s commands in the human’s own shell history and terminal, which makes the audit trail about the commands consistent with everything else the human runs. Mixed models, where some commands are human-run and some agent-run, blur that record.

Least privilege for the agent’s identity

An agent should run under an account that can do its job and nothing more. If the job is writing to one repo and running one test suite, the account needs read-write on that repo and the ability to run exactly those commands, not membership in sudo.

  • Give the agent a dedicated user, never a shared admin account.
  • Scope sudo entries to the specific commands the workflow needs.
  • Block interactive shells where the agent only needs non-interactive execution.
  • Rotate the agent’s credentials like any other machine identity.

The same identity hygiene that applies to humans applies to agents. If you are not already modeling revocable per-person access, the SSH access review guide is the right starting point, because an agent is, from the server’s point of view, another access holder.

For agents in particular, the dedicated-user rule is worth more than it looks. A shared admin account used by an agent means the audit log cannot separate “the agent restarted nginx” from “the engineer restarted nginx,” and the whole point of the approval pattern collapses. The agent’s own identity makes its actions reviewable.

Where the audit trail matters

When an agent touched a production host and something broke, the postmortem needs an answer to who approved which command and when. That requirement pushes toward logging every command the session executes, whether typed by a human or emitted by an agent, to the same per-command record described in what a per-command audit log catches. The approval logs and the command logs together reconstruct the whole story.

The session-context problem: which host are we on?

One failure mode deserves its own section because it silently defeats every other control: the agent, or the human, loses track of which host the session is on. A command that is perfectly safe on a dev box can be destructive in production, and the only difference is the hostname in the prompt. The fix is structural: make the session context visible at all times, and require the approval prompt to name the host, not just the command.

This is exactly the class of problem an SSH manager with per-session context solves, and it is why the assisted-SSH discussion in the AI assistant analysis spends as much time on context as on capability.

How to run agents without SSH at all, sometimes

Not every agent task needs live SSH access. For tasks that only touch the repository, a CI pipeline or a sandbox that clones the repo is the safer home: no credentials on the box, no blast radius on the fleet. The guide to running AI agents on remote servers covers when live SSH is genuinely required versus when it is just convenient.

A useful test for whether live access is required: could the agent’s outcome be produced by a pull request? If yes, the default workflow should be agent proposes changes, human merges after review. Live SSH should be reserved for the cases where the agent must interact with the running environment itself, and even then only under the approval pattern.

Approval fatigue is real. Scope the gate, do not skip it

The objection to command approval is that it slows everything down. The answer is not fewer gates, it is narrower ones. Read-only agents on a dev box can run with light oversight. An agent that can reach production should pause before every write, and the account that backs it should not be the same account used by humans. Scope the capability and the approval cadence together: blast radius first, speed second.

What an approval workflow looks like in practice

A concrete loop makes the pattern real. The agent reads the repo, proposes a command, and posts it into the session transcript with the hostname prefixed. The human evaluates three things in order: is this the right host, is this the right command for the task, and does the account it will run under have the least privilege needed. Approved commands execute; everything else stays as text. That discipline stays identical no matter how fast the agent is.

The transcript matters as much as the gate. Because the approved command, the host, and the timestamp all live in one record, the postmortem question “what did the agent actually do here” has a single place to look. The same record is what turns a vague “an AI made a change” into a reviewable event.

Why context beats raw speed for agent safety

The common thread across every safe agent pattern is context. An agent that knows the host, the environment, and the blast radius of its commands proposes better and fails safer. That is the argument for keeping agent sessions inside an infrastructure tool rather than in a bare terminal: the session already carries the host identity, so the approval prompt can show it. A bare-shell agent has no idea which box it is on, and neither does the person approving its output.

Building an automated command allow-list for AI agents

To prevent human approval fatigue while preserving security boundaries, progressive engineering teams implement command classification rules. Commands are divided into pre-approved read-only operations and gated state-changing operations:

# Safe read-only commands (Auto-approved):
allow: git status, git diff, cat, ls, grep, tail -n *, ss -ltnp

# Sensitive operations (Mandatory interactive human confirmation):
gate: sudo *, rm *, systemctl *, docker restart *, composer update

# Hard forbidden (Instant block and session termination):
deny: rm -rf /, dd if=*, chmod -R 777 *, mkfs *

By automating approval for safe diagnostic reads while requiring affirmative human confirmation for file mutations and service restarts, teams achieve high agent velocity without sacrificing operational safety.

Sandboxing agents with Docker and restricted shells

When you want an AI agent to freely explore dependency graphs and compile tests without risk to the host OS, deploy the agent inside an ephemeral Docker container with read-only root filesystems and explicit bind mounts:

docker run --rm -it \
  --read-only \
  --network none \
  --volume /var/www/app:/workspace:rw \
  --user 1000:1000 \
  termique/agent-sandbox:latest

With --network none and --read-only, even a catastrophic prompt injection or hallucinated command is trapped inside the throwaway container, completely isolated from server networking, credentials, and host storage.

The takeaway

  • Command approval is the control point that makes agents safe to run.
  • Agents propose, humans execute; intent is never the boundary, confirmation is.
  • Least-privilege identities for agents, scoped sudo, and rotated credentials.
  • Audit the commands agents run the same way you audit a human’s.
  • Make the host visible in every approval, or the approval is meaningless.

An agent is a colleague that works fast and never sleeps, so it needs the same guardrails the slow ones have. termique is a free SSH manager we build, and its per-session assistant proposes commands and waits for your approval through exactly this pattern. termique.app, if you are curious.

Try termique free.

SSH manager with end-to-end encrypted credentials, AI assistant, and cross-device sync.

Download free

Keep reading

All articles ⟶