maisecrets menu

maisecrets / SSH

Ask before the agent changes a server

With ssh_consent on (it is off by default), maisecrets asks before the agent changes a server. An agent with your SSH keys can run any command on any host it reaches, also when no secret is in the command. A permission rule on “ssh” matches only the start of a command, so “cd x && ssh …” passes it.

The problem is the mode you work in. In bypass permissions mode, and in auto mode, Claude Code asks you nothing: an agent with your SSH keys runs every command on every host it reaches. You want it to read logs and status on its own, but not to restart a service or change a file without you. ssh_consent is a check of its own, in a maisecrets hook: it lets the reads run and asks before each write.

YOUR COMPUTER AI agent ssh web1 uptime ssh web1 'systemctl restart app' maisecrets reads every ssh call web1 your server You yes or no a read: runs asks first a write: after a yes
A read goes to the server at once. A write goes only after you say yes, also when it hides behind cd … && or timeout.

What happens with ssh_consent on

ssh web1 uptime                      runs: a read
ssh web1 'cat /etc/app.conf'         asks: the content of a file
cd deploy && ssh web1 'systemctl restart app'   asks: a write
  • A read runs. A remote command from a short list that prints only metadata about the host: uptime, df -h, free, uname, ls, systemctl is-active.
  • Every write asks. Any other command, a login shell, sudo, a copy, a tunnel. A yes allows that one command. maisecrets reads the ssh call also behind cd … &&, timeout, nohup, env and sudo, and for scp, sftp, rsync and mosh too.
  • A host you trust for a while: type maisecrets: allow ssh web1 as your own prompt. Writes to that host run without a question for 8 hours, in that session.
  • Your own lab hosts can be autonomous: /maisecrets:settings ssh_autonomous_hosts add ops1. Writes there never ask; every other host still asks.

Turn it on with /maisecrets:settings ssh_consent on as your own prompt. It is off by default, and a machine policy can set it.

Three lists of hosts

ListWhat it allowsHow longHow you set it
A host you trust for a whilewrites to that host run without a question8 hours, in that sessionmaisecrets: allow ssh web1, typed by you
Autonomous hostswrites never ask, in every sessionuntil you remove the host/maisecrets:settings ssh_autonomous_hosts add ops1
The sandbox allowlist of Claude Codethe only hosts that may get a value on stdinuntil you change itsandbox.network.allowedDomains in ~/.claude/settings.json

Every other host asks for each write. A host is as the ssh call writes it: root@web1 and web1:2222 are other hosts than web1. A group in ssh_host_groups names several hosts at once.

A value for a server goes on stdin

Sometimes the agent must search a log on your server for a value that it knows only as a placeholder. maisecrets lets the value go to your own servers on one condition: the command runs in the Bash sandbox of Claude Code, where the proxy admits only the hosts you allow. Then the value goes on stdin, and the command text holds only the placeholder:

printf '%s' ⟦EMAIL_c3⟧ | ssh aux01 'grep -F -f - /var/log/mail.log'

maisecrets refuses a value inside the arguments of ssh, a remote side that runs its program from stdin (bash, sh -s, | sh), and an own proxy or jump host.

Limits

  • The list of reads is a heuristic, not a guarantee. A form that maisecrets cannot read, such as a host built at run time (ssh $HOST) or an option that sends the connection elsewhere, asks every time.
  • The sandbox limits where the connection goes, not what the remote side does with a value.
  • In Codex, the route with a value refuses: Codex has no host allowlist.

All forms and options: README.