Skip to content
Go back

SSH Agent Forwarding: How It Works

By SumGuy 5 min read
SSH Agent Forwarding: How It Works

You’re on a jump host. You need to SSH to an internal server. You don’t want to copy your SSH key to the jump host.

Solution: SSH agent forwarding. It lets the jump host borrow your SSH key without actually having it.

Sounds great. In practice? It’s a security landmine.

How Agent Forwarding Works

Normal SSH:

Your machine
↓ (SSH key loaded in ssh-agent)
→ Jump host
↓ (your key stays local)
→ Internal server (jump host uses your key)

With agent forwarding (ForwardAgent yes):

Your machine (ssh-agent running, with your key)
→ Jump host
↓ (jump host can ask your agent for signatures)
→ Internal server (jump host requests signature from YOUR agent)

The jump host never sees your key. It just asks your local agent: “Can you sign this? Pretty please?”

Seems safe, right?

The Security Risk

Root on the jump host can steal your key.

Here’s how:

Terminal window
# You're on jump host with agent forwarding enabled
jump$ SSH_AUTH_SOCK=... # env var points to your agent socket
# Attacker (who is root on jump host) hijacks the socket:
jump# netcat $SSH_AUTH_SOCK
# Or uses ssh-keyscan or other tools to get your agent to sign things
# Now attacker can SSH anywhere you can SSH

This isn’t hypothetical. If the jump host is compromised, your key is compromised.

When Agent Forwarding Is Safe

Almost never.

The only scenario: You fully trust the jump host operator, and you’ve verified the host key is correct.

Terminal window
# One-time: check the jump host fingerprint
ssh-keyscan jump.example.com | ssh-keygen -lf -
# Compare manually with your sysadmin

Even then, it’s paranoid to avoid it.

The Better Way: ProxyJump

Don’t forward your agent. Use ProxyJump instead.

~/.ssh/config
Host jump
HostName jump.example.com
User admin
Host internal
HostName internal-db.local
User appuser
ProxyJump jump

Now:

Terminal window
$ ssh internal
# SSH establishes connection: local → jump → internal
# Your key never leaves your machine
# Jump host never sees your key

This is secure by design. The jump host is just a tunnel, not a party to your authentication.

If You Must Forward

(You shouldn’t.)

~/.ssh/config
Host unsafe-jump
HostName jump.example.com
ForwardAgent yes

Then:

Terminal window
$ ssh unsafe-jump

Now:

Terminal window
jump$ ssh internal-server
# Uses your agent to authenticate
# But root on jump can now steal your key!

How to Know If Agent Forwarding Is Enabled

On the server:

Terminal window
jump$ echo $SSH_AUTH_SOCK
/tmp/ssh-XXXXXX/agent.12345

If this is set, you have agent access. If root can read it, your key is at risk.

Terminal window
jump$ ls -la $SSH_AUTH_SOCK
srwx------ 1 user user 0 Apr 26 10:00 /tmp/ssh-XXXXX/agent.12345
only you can access it (good)
# But root can still access anything!

Testing If Agent Forwarding Works

Terminal window
$ ssh -v jump
...
debug1: Sending environment variable SSH_AUTH_SOCK

If you see that, agent forwarding is active.

Test if it actually works:

Terminal window
jump$ ssh-add -l
# Lists keys in your local agent
3072 SHA256:xxxxx ~/.ssh/id_rsa (RSA)
jump$ ssh internal-server
# Uses one of those keys to authenticate

If ssh-add -l works, agent forwarding is working.

Disabling Agent Forwarding

Global default:

~/.ssh/config
Host *
ForwardAgent no

Per-host:

~/.ssh/config
Host unsafe-jump
ForwardAgent no
Host trusted-jump
ForwardAgent yes

Command-line override:

Terminal window
ssh -o ForwardAgent=no jump

Real-World: Jump Host Chain

~/.ssh/config
# Don't forward agent
Host jump
HostName jump.example.com
ForwardAgent no
# Use jump as proxy, don't forward agent
Host internal
HostName internal.local
ProxyJump jump
ForwardAgent no

Now:

Terminal window
$ ssh internal
# local → jump → internal
# At no point does agent forwarding happen
# Your key is safe

When People Use Agent Forwarding (And Why They’re Wrong)

“I need to SSH from jump to internal. How else do I do it?”

Answer: ProxyJump. That’s literally what it’s for.

“But I have an old SSH version that doesn’t support ProxyJump.”

Answer: SSH 7.3+ (2016). Upgrade.

“We use sshpass / passwords.”

Answer: Use SSH keys instead. Safer.

“Our jump host is internal and we trust it.”

Answer: Until it’s not. And you don’t. “Internal” is a policy. Attackers don’t care.

The Real Risk

Agent forwarding is a privilege escalation vector. Once an attacker is on the jump host, they can:

  1. Use your agent to SSH to other servers
  2. Use your agent to sign other requests (if you use SSH for authentication elsewhere)
  3. Steal credentials stored in agents (rare, but possible)

ProxyJump sidesteps all of this. The jump host becomes a dumb tunnel.

Best Practice

~/.ssh/config
Host *
# Default: no agent forwarding
ForwardAgent no
# Jump hosts
Host jump
HostName jump.example.com
# Still no forwarding, we use ProxyJump instead
# Everything behind jump
Host *.internal
ProxyJump jump
# No forwarding needed

No agent forwarding. Ever. Problem solved.

TL;DR

Your key stays local. Everyone’s happy.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it may appear here.


Previous Post
How to Actually Read `systemctl status` Output
Next Post
Is Your Linux Server Destroying Its SSD?

Related Posts