You can limit what an SSH key is allowed to do by adding options in front of it in authorized_keys. For a key used by a script, combine restrict, a forced command and a from list. A stolen key then runs one command, from named addresses, with no forwarding.
Where the options go
Each line in authorized_keys holds an optional options field, then the key type, the base64 key and a comment. Options are comma separated, and the sshd manual says spaces are not allowed except inside double quotes. Option names are not case sensitive.
A line looks like this:
restrict,from="192.0.2.0/24",command="/usr/local/bin/run-backup" ssh-ed25519 AAAA... backup-job
The three that matter most
restrict. Turns off port forwarding, agent forwarding and X11 forwarding, disables PTY allocation, and disables running ~/.ssh/rc. The manual adds that if future restriction options are created, restrict will include them. You can then add back only what you need with options such as pty or port-forwarding.
command="...". The given command runs whenever this key authenticates, and any command the client supplied is ignored. The manual's example is a key that permits remote backups and nothing else. The original client request is available in the SSH_ORIGINAL_COMMAND environment variable. The manual warns that without a restriction, the client may still ask for TCP and X11 forwarding, which is why restrict goes with it.
from="pattern-list". In addition to the key, the client's host name or IP address must match the list. CIDR notation works. The manual explains the purpose: a key alone trusts nothing but the key, so a stolen key lets an intruder log in from anywhere, and from makes that harder. Note that name based patterns depend on DNS, so addresses are the tighter choice.
Other useful options
no-agent-forwardingandno-port-forwardingfor single bans.permitopenandpermitlistento limit wheressh -Landssh -Rforwarding may go.expiry-timeto make a key stop working at a given date or time, written as a date or time with an optional Z for UTC.verify-requiredfor FIDO keys, which makes a PIN or similar check part of every use.
Handling SSH_ORIGINAL_COMMAND
A forced command that passes SSH_ORIGINAL_COMMAND to a shell reintroduces the problem. If the wrapper allows several operations, parse the value strictly against a list of known words, and reject everything else. A small script that takes no input is safer than one that does.
Test it
From the client, try the key with an unrelated command, for example ssh -i key host id. It should run the forced command, not id. Try from a different network and confirm the from rule refuses. Keep an admin session open while you test, so a typo cannot lock you out.
Also remember that ForceCommand in sshd_config can supersede a key level command, per the manual, so check both places when behavior surprises you.
For people logins you probably want more than a restricted key. See requiring a key and a second factor.
Safeguard's policies, gates and guardrails cover pipelines and agents, and a free scan is at gold.safeguard.sh/scan.
Quick check
Does command= alone stop port forwarding?
No. The manual says the client may still request TCP and X11 forwarding unless you forbid it, for example with restrict.
What does the from option protect against?
A stolen key used from an unexpected network. The client address or name must match the list in addition to presenting the key.
Sources
- sshd(8) manual page, Debian manpages, AUTHORIZED_KEYS FILE FORMAT
Last reviewed: 19 October 2026.