SSH Agent

Tip

Try it first

Chapter 2 of the interactive tutorial shows how agent forwarding exposes access beyond the first intercepted server — in a safe environment with no real target needed.

$ ssh-mitm tutorial

See Get Started for the full tutorial list.

Quickstart

SSH-MITM can expose a client’s forwarded SSH agent as a local Unix socket, giving auditors direct access to the agent without touching the client. (New to SSH agents? See Background: What is an SSH Agent? below.)

Start SSH-MITM with agent socket exposure:

ssh-mitm server --remote-host <target-host> --expose-agent-socket

When a client connects with agent forwarding enabled (ssh -A), SSH-MITM prints ready-to-use commands to the log:

ℹ <session-id> - agent socket ready - docs: https://docs.ssh-mitm.at/audit_guide/sshagent.html
ℹ <session-id> - ssh-add:  SSH_AUTH_SOCK=/tmp/ssh-mitm-abc12345.agent ssh-add -l
ℹ <session-id> - ssh:      SSH_AUTH_SOCK=/tmp/ssh-mitm-abc12345.agent ssh alice@<target-host>

Copy any line directly from the log and run it. The SSH_AUTH_SOCK variable is all that is needed — every standard agent client (ssh-add, ssh, git, …) honours it.

Note

Agent forwarding works for interactive SSH sessions, but also for scp and sftp when the client uses OpenSSH 8.4 or later. SSH-MITM intercepts the agent regardless of which protocol the client uses.

Auditing the Forwarded Agent

This section walks through a complete agent audit using ssh-add with the SSH_AUTH_SOCK printed by SSH-MITM. All commands run on the SSH-MITM host.

Set the variable once for the current shell to avoid repeating it:

export SSH_AUTH_SOCK=/tmp/ssh-mitm-abc12345.agent

Listing keys

Show which keys the client currently holds:

ssh-add -l          # fingerprints (short)
ssh-add -L          # full public keys (useful for further analysis)

A client that connects with ForwardAgent yes but no keys loaded will show The agent has no identities.

Adding a key

A key can be added to the forwarded agent — for example to test whether a specific key grants access to other systems in scope:

ssh-add /path/to/private_key

The key is available in the agent for the duration of the session.

Warning

Adding a key to a client’s agent modifies their session state and is immediately visible to the client. Only do this in explicitly authorised audits.

Removing keys

Remove a single key (pass the corresponding public key file or private key):

ssh-add -d /path/to/private_key

Remove all keys at once:

ssh-add -D

Warning

Removing keys from a client’s agent is immediately visible to the client if they run ssh-add -l themselves. Use this only in authorised audits.

Locking and unlocking the agent

An SSH agent can be locked with a password so that no operations are possible until it is unlocked again. This is useful for testing whether automated processes depend on an always-unlocked agent.

Lock the agent:

ssh-add -x          # prompts for a lock password

Unlock the agent:

ssh-add -X          # prompts for the same password

Note

Most agents reject an empty lock password. The client’s ssh process will fail with sign_and_send_pubkey: signing failed for RSA (or similar) while the agent is locked.

Warning

Locking the agent is immediately visible to the client — any ongoing or new SSH operation that requires the agent will fail. Use this only in explicitly authorised audits.

Authenticating against other hosts

Use the client’s agent to open an SSH connection to any host the client’s keys grant access to:

ssh alice@<other-host>

This lets an auditor verify which systems are reachable with the intercepted agent — a key question in lateral-movement assessments.

Background: What is an SSH Agent?

SSH private keys are usually stored encrypted on disk. Without an agent, SSH must decrypt the key file on every connection — meaning you have to type your passphrase every single time.

An SSH agent is a small background program that solves this: you load your key into it once, enter the passphrase once, and the agent keeps the decrypted key in memory for the rest of your session. Every SSH connection then asks the agent to sign the authentication challenge silently, without prompting you again.

$ ssh-add ~/.ssh/id_rsa      # load key — passphrase entered once
Enter passphrase for /home/alice/.ssh/id_rsa: ********

$ ssh alice@server1          # no passphrase prompt
$ ssh alice@server2          # no passphrase prompt

The agent communicates with SSH clients through a Unix socket. Its path is stored in the SSH_AUTH_SOCK environment variable, which SSH reads automatically. The socket file lives in a temporary directory under /tmp — and any process that can access it (including the root user) can use all keys the agent holds.

To limit the damage if a machine is compromised, keys can be protected with a FIDO2 hardware token: every signing operation requires a physical button press on a separate device, which software alone cannot bypass. SSH-Askpass offers a software-only alternative, but it can be bypassed by malware or an attacker who controls the desktop. FIDO2 is always the stronger choice.

SSH Agent Forwarding

Agent forwarding lets you use your local SSH agent on a remote server — without ever copying your private key there.

A typical scenario: A developer logs in to a dev-server at work. From there they want to push code to a git-server. Their private key lives on their workstation. Without forwarding they would have to copy the key to dev-server (a security risk) or create a separate key just for that server.

With ssh -A, the SSH connection tunnels signing requests back to the local agent:

        sequenceDiagram
    participant L as workstation [agent]
    participant D as dev-server
    participant G as git-server

    L->>D: ssh -A
    D->>G: ssh
    note over G: uses workstation's agent
    

The private key never leaves the workstation. dev-server only receives the signed authentication response, not the key itself.

Logfile Inc. assessment

In the Logfile Inc. scenario, this is Sarah King (sking) connecting to web01 and then on to LogfileGit. The company-wide SSH config template — introduced by Lisa Chen (lchen) without fully understanding the implications — sets ForwardAgent yes for all connections. Chapter 2 demonstrates the interception.

The security risk: While Alice’s session is active, the forwarded agent socket on dev-server is accessible to the root user — and to any attacker who gains root access. They can use that socket to authenticate to any system Alice’s key grants access to, without ever seeing the private key. When Alice closes her session, the socket disappears.

Agent forwarding is available for interactive shell sessions and, since OpenSSH 8.4, also for scp and sftp.

Warning

Only forward your agent to servers you fully trust. A compromised server with root access can silently use your agent for as long as your session is open. If agent forwarding is unavoidable, protect your key with a FIDO2 token — every signing operation then requires a physical button press that a remote attacker cannot trigger.

Security considerations

The security risks of agent forwarding are specified in draft-ietf-secsh-agent-02 §6. The core principle: anyone with access to a forwarded agent socket has the same power as someone holding the private key — for as long as the session remains open.

SSH-MITM — abusing a forwarded SSH agent

SSH-MITM acts as a full proxy: it terminates the client connection and opens a separate connection to the real server independently. When the client forwards its agent, SSH-MITM receives it and uses it to authenticate against the real server on the client’s behalf — making a complete man-in-the-middle attack possible even with public-key authentication.

In the tutorial scenario (Chapter 2), Sarah King (sking) connects to web01 with ssh -A. SSH-MITM intercepts the connection, receives the forwarded agent, and authenticates to the real server as sking. Her session continues as normal while the agent is fully accessible to the auditor.

Host-bound public key authentication

OpenSSH 8.9 introduced publickey-hostbound-v00@openssh.com to prevent signature replay attacks: the client’s signature is cryptographically bound to the host key of the server it is connecting to, so a captured signature cannot be used against a different server.

Tip

For protocol details, wire formats, and a full walkthrough of destination constraints, see publickey-hostbound Authentication.

In a proxy scenario this works exactly as designed. The client connects to SSH-MITM and produces a signature bound to SSH-MITM’s host key — correct behaviour, because SSH-MITM is the server it is talking to. SSH-MITM then opens a separate connection to the real server and requests a fresh signature from the forwarded agent, bound to the real server’s host key. No replay takes place on either leg.

What about FIDO2 keys? When a FIDO2-protected key is used, every signing operation requires a physical button press. With a straightforward proxy attack, the user would have to confirm twice: once for SSH-MITM and once for the real server — which is suspicious. This is where the trivial authentication attack comes in: by authenticating the client to SSH-MITM without using the private key at all, the attacker reduces the number of confirmations to exactly one — the one the user expects.

See also

publickey-hostbound Authentication — full protocol details, wire formats, and a complete walkthrough of the destination-constraint mechanism.

SSH-Agent Breaking

When a client connects without agent forwarding enabled, SSH-MITM can send an unsolicited request asking the client to forward its agent anyway. A correctly configured SSH client will reject this request and close the session — this is the expected and secure behaviour.

This feature is useful for auditing whether clients are hardened against unauthorized agent forwarding requests:

ssh-mitm server --remote-host <target-host> --request-agent-breakin

Note

If the client closes the session, it is hardened against this request. If the session stays open, the client ignored the request — but the agent is not necessarily forwarded. Only if the client also forwards its agent does the forwarded agent socket become available for interception.