You SSH into a bastion, and now you need to git pull from a private repo or hop to a second server — but your key lives on your laptop, not the bastion. The one-line fix that always comes up is ssh -A: agent forwarding. It works instantly, which is exactly why it’s everywhere, and exactly why it deserves a second look before you make it a habit.
What agent forwarding actually does
Start with the agent itself. Your ssh-agent holds your unlocked private keys in memory on your local machine. When you connect somewhere, the agent answers the server’s authentication challenge — it proves you hold the key without the key ever leaving your machine. That part is good and normal.
Agent forwarding extends that reach one hop further. With -A (or ForwardAgent yes), your ssh client opens a socket on the remote host that proxies signing requests back to your local agent. So a process on the remote host — say, ssh to a second server, or git over SSH — can ask your agent to sign, and authenticate as you, without the key being present there.
The key detail people miss: the key still never leaves your laptop. What you’ve exposed is not the key but live use of it — a channel back to your agent that’s open for as long as your session is. And anything on that remote host that can find the socket can use it.
Why that’s dangerous
The socket is the problem. Its path sits in an environment variable (SSH_AUTH_SOCK) on the remote host, and the socket honours signing requests from whoever can reach it.
- Root on the bastion can use your agent. Anyone with root on that host — a legitimate admin, or an attacker who has compromised it — can locate your forwarded socket and ask your agent to authenticate as you to any server your keys reach. They can’t copy the key out, but they don’t need to: while your session is open, they can log in wherever you can.
- It turns one popped box into fleet-wide reach. A bastion is a shared, internet-facing machine — precisely the kind that gets compromised. Forward your agent to it and a single break-in inherits the full reach of your keys, live, for the duration of your session. That’s a lateral-movement dream.
- You won’t see it happen. There’s no prompt, no log on your side, nothing that says “someone just borrowed your identity.” The abuse looks exactly like normal use.
The mental model that keeps you honest: for as long as you forward your agent to a host, you are effectively trusting that host with your keys. Not the key bytes, but everything the keys can do.
When it’s actually fine
Agent forwarding isn’t evil — it’s a sharp tool used carelessly. It’s genuinely reasonable when:
- The remote host is one you fully control and trust — single-user, hardened, not shared with anyone.
- The session is short and supervised, not a tunnel you leave open all day.
The risky case is the common one: forwarding to a shared bastion, a multi-tenant jump box, or any machine where you’re not the only one with (or able to get) root.
What to use instead
For the most common reason people forward an agent — “I just need to reach the next server” — there’s a cleaner tool.
1. ProxyJump (-J) — the real fix for reaching the next hop. Instead of logging into the bastion and launching ssh from there, ProxyJump tunnels through it and authenticates end to end from your laptop to the target. The bastion only forwards encrypted bytes; it never sees your agent or your key.
ssh -J bastion.example.com db.internal
No agent is exposed on the bastion, so there’s no socket for root to abuse. This is the right answer for bastion architectures, and it’s worth its own read — see ProxyJump: reach servers behind a bastion.
2. ssh-add -c — require confirmation for every use. If forwarding is genuinely unavoidable, at least make each signing request visible. Add your key to the agent with -c and every use pops a local confirmation prompt:
ssh-add -c ~/.ssh/id_ed25519
Now a forwarded host can ask, but nothing signs without you clicking OK on your own machine. Pair it with -t to expire the key from the agent after a set time (ssh-add -t 3600).
3. Never turn forwarding on globally. The worst setup is ForwardAgent yes in a Host * block, silently forwarding everywhere. Keep it off by default and enable it only for the specific host that truly needs it:
Host trusted-build-box
HostName build.example.com
ForwardAgent yes
Everything else gets no forwarding at all. (More on structuring the file in the ssh_config guide.)
4. Put a dedicated key on the box. If the remote host needs ongoing SSH access of its own — pulling from a git host, say — give it its own limited key or deploy key rather than lending it your personal agent. A key scoped to one repo is a far smaller thing to lose than your identity. (On picking the key, see Ed25519 vs RSA.)
The rule of thumb
Forward your agent only to hosts you’d trust with your keys — because for the length of the session, that’s what you’re doing. For “reach a server behind a bastion,” reach for ProxyJump: it gives you the hop without lending anyone your identity.
How Termalin fits
Termalin leans on the safer pattern by default. Your keys stay in a one-unlock agent on your machine, and you reach a target behind a bastion by attaching a jump host to the saved server — so the connection routes through the gateway while the key stays local and no agent socket is ever placed on the bastion for someone to abuse. Each hop’s server identity is verified on first connect, and the whole host list syncs across your machines end-to-end encrypted.
And when the thing on the far end is an AI agent rather than you, the custody idea goes all the way: the agent never holds a key at all — Termalin signs on its behalf, scoped per host and per command. That’s the same instinct as don’t forward your agent to something you don’t fully trust, taken to its logical end. More on that in giving a local LLM safe SSH access.
Termalin is a free, cross-platform SSH client that keeps your keys in a one-unlock agent and connects through jump hosts — download it, or read how it handles your keys safely.