Join our Newsletter — 33% off our NHI Course
Home› Guides› SSH Agent Forwarding vs ProxyJump: Reaching Hosts Without…
Guide Endpoint Security

SSH Agent Forwarding vs ProxyJump: Reaching Hosts Without Exposing Your Keys

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 14 November 2026 16 min read
On this page

Agent forwarding lends your keys to every host you pass through, so anyone with root on a bastion can sign in as you elsewhere while your session is open. Engineers reach for ForwardAgent because it makes multi-hop access painless, and the private key never leaves the laptop, which feels safe. The OpenSSH manual is blunt that it is not: a user who can bypass file permissions on the remote host can use the forwarded agent socket, even though they cannot copy the key. ProxyJump solves the same reachability problem by tunnelling an end-to-end session through the jump host instead. This guide compares the two threat models, explains when forwarding is still justified and how to constrain it, and sets out bastion and client configuration for teams who own SSH access. Server hardening in general is covered in the OpenSSH Server Hardening Guide; this page stays on the multi-hop decision.

Key takeaways

  • Forwarding exposes key use, not key material. The ssh_config manual states that an attacker on the remote host cannot obtain key material from the agent but can perform operations on the keys, which is all they need to authenticate onward (ATT&CK T1563.001 SSH Hijacking).
  • ProxyJump keeps authentication end to end. The client opens a TCP forwarding through the jump host and authenticates directly to the target, so the jump host relays encrypted traffic and never holds a usable signing channel.
  • Use ProxyJump by default, forwarding by exception. The ssh manual itself suggests a jump host as a safer alternative to -A. Forwarding remains valid where the remote host must itself authenticate onward, such as a git pull on a build box.
  • Constrain any key you forward. Destination constraints (ssh-add -h, OpenSSH 8.9 and later), confirm-on-use (-c), short lifetimes (-t) and FIDO keys with user presence each narrow the window, but none stops a malicious hop from using what you forwarded to it.
  • Design the bastion as a relay, not a shell. Allow local TCP forwarding to an allowlisted set of destinations, refuse agent forwarding and interactive shells, and log every channel, so a compromised bastion yields as little as possible.

How each option works

Agent forwarding (ForwardAgent, ssh -A)

Your local ssh-agent holds decrypted private keys and signs authentication challenges on request. With forwarding on, sshd on the first hop creates a Unix-domain socket on that host and sets SSH_AUTH_SOCK in your session. When you run ssh from the first hop to a second host, the second host's challenge travels back over your existing connection to the agent on your laptop, which signs it. The key never crosses the network, which the ssh-agent manual confirms: passphrases and private keys never go over the network.

The weakness is the socket on the intermediate host. The ssh-agent manual describes the agent socket as accessible only to the current user, "but is easily abused by root or another instance of the same user". Anyone who can open that socket while your session is live can ask your agent to sign for any host your keys open. Since OpenSSH 10.1 (released 6 October 2025), forwarded sockets are created under ~/.ssh/agent rather than /tmp, which reduces casual discovery but does nothing against root.

ProxyJump (ssh -J)

ProxyJump tells the client to make an SSH connection to the jump host first, then establish a TCP forwarding from there to the ultimate target. The client then runs a second, complete SSH handshake through that tunnel: host key verification of the target, key exchange and user authentication all happen between your laptop and the target. Multiple hops can be chained with commas. The jump host sees that you opened a channel to a given host and port and passes encrypted bytes; it has no agent socket to abuse and cannot read or alter the inner session.

Side by side

PropertyAgent forwardingProxyJump
Where the target authenticates youOn the intermediate host, which relays the signing request back to your agentDirectly from your client, through a tunnel
What a root user on the hop gainsUse of every loaded key for as long as your session lastsKnowledge of the destination host and port, plus ability to drop or delay traffic
Target host key verified byThe intermediate host's known_hostsYour own known_hosts
Server-side setting needed on the hopAllowAgentForwarding yes (the default)AllowTcpForwarding yes or local, with PermitOpen to restrict destinations
Works when the hop must act for youYes: git, scp or ssh run on the hop can use your keysNo: the hop gets no credentials
Interactive shell on the hopRequiredNot required; the bastion can refuse shells
ATT&CK relevanceT1563.001 SSH Hijacking via the agent socketT1021.004 SSH lateral movement only with credentials stolen elsewhere

The threat model in detail

MITRE ATT&CK T1563.001 describes adversaries hijacking existing SSH sessions to move laterally, either by compromising the agent or by having access to the agent's socket, and notes that with root access the hijack is likely trivial. Three scenarios cover most real exposure.

  • Compromised shared bastion: an intruder with root on a jump host used by the whole operations team sees a fresh agent socket every time an engineer connects with -A. Each one is a window into that engineer's reach: production databases, other bastions, code hosting. The intruder never needs to crack a passphrase.
  • Malicious or over-privileged administrator on the hop: the same mechanics apply to an insider with sudo on the intermediate host. Separation of duties between bastion administrators and production owners collapses the moment forwarding is common.
  • Forwarding by accident: a wildcard Host * block with ForwardAgent yes forwards your agent to every server you touch, including third-party and customer hosts you have no reason to trust.

ProxyJump changes what a compromised hop can do. It can refuse to forward, redirect your connection to an impostor (which your own known_hosts check will flag), or record traffic metadata. It cannot sign anything as you. The residual risk moves to the client: your laptop must hold the keys and the known_hosts entries, which is why ProxyJump pairs naturally with a Privileged Access Workstation for high-value targets.

Constraining agent forwarding when you must use it

Some workflows genuinely need the remote host to authenticate onward: pulling a private repository on a build host, running rsync between two servers, or an orchestration host that fans out to many nodes. Before allowing forwarding, consider whether a dedicated, scoped machine credential on that host would be cleaner (see the SSH Key Management Guide). Where forwarding stays, layer the following controls.

ControlHow it is setWhat it stopsWhat it does not stop
Destination constraintsssh-add -h with host, user@host or hop>user@host entries; OpenSSH 8.9 or later on agent, client and serversUse of the key for any destination or path not listed; the agent refuses itA malicious hop using the key for a destination you did list through that hop
Confirm on usessh-add -c, or AddKeysToAgent confirm in ssh_config; needs ssh-askpassSilent use: each signature raises a prompt on your desktopApproval fatigue; the prompt shows no destination or path, so a well-timed request is easy to approve
Short lifetimessh-add -t or ssh-agent -tKeys lingering in the agent all day; without -t the default lifetime is foreverAbuse within the lifetime
FIDO key with user presenceed25519-sk or ecdsa-sk key requiring touch, optionally PINUnattended signing: every signature needs a physical touchA touch you give for your own login being used by a request you did not intend
Separate agent per trust zoneIdentityAgent pointing to a dedicated agent socket for that Host block, with IdentitiesOnlyExposure of unrelated keys (production, personal, code signing) to a lower-trust hopAbuse of the keys in that zone's agent

The OpenSSH project's own write-up on agent restriction is candid about the limits. Destination constraints rely on protocol extensions in ssh-agent, ssh-add, ssh and sshd on most participating hosts, map host names to host keys through your known_hosts at the time you add the key, and are immutable once loaded. If an agent is forwarded to an attacker-controlled host, that host can still use the keys permitted there. Confirmation prompts are described as seldom used and somewhat easy to phish, and FIDO user presence as offering a little more defence while being similarly phishable. Treat these as damage limitation, not a fix. FIDO details, including the agent's default refusal to sign web authentication requests, are in the Security Keys for SSH guide.

Designing the bastion for ProxyJump

A bastion that only relays connections is far less valuable to an intruder than one where engineers log in, keep shells open and forward agents. The sshd_config manual warns that disabling agent, TCP or StreamLocal forwarding "does not improve security unless users are also denied shell access", and the inverse holds for a relay bastion: the protection comes from combining no shells with tightly scoped forwarding.

  1. Give relay users no shell: put jump users in a dedicated group and, in a Match Group block, refuse interactive sessions (for example a ForceCommand that exits), set PermitTTY no and X11Forwarding no.
  2. Allow only outbound local forwarding: AllowTcpForwarding local, AllowAgentForwarding no, AllowStreamLocalForwarding no and PermitListen none so the bastion cannot be used for reverse tunnels.
  3. Allowlist destinations: PermitOpen with the host:port pairs (or address ranges per Match block) that the group may reach. By default all forwarding requests are permitted, so leaving this unset turns the bastion into an open relay for anyone with a valid key.
  4. Remember first-match ordering: when a keyword appears in several satisfied Match blocks, only the first instance applies, so place the most restrictive blocks first and test with sshd -T using connection parameters.
  5. Keep administration separate: bastion administrators connect through a different path and group with shells, MFA and session recording; relay users never share it. The Securing the jump host and bastion itself page covers OS hardening, patching and monitoring of the bastion host.
  6. Prefer certificates for scale: SSH user certificates with short validity and principals let the bastion and targets trust one CA rather than thousands of authorized_keys entries, and certificate host keys make destination constraints easier to maintain. See the SSH Protocol and Certificate Authority Guide.

A target host behind a relay bastion should also accept connections only from the bastion's addresses (a firewall rule or a from= option on keys) and set DisableForwarding yes unless a Match block grants an owned exception.

Client configuration that makes the safe path the easy path

Most forwarding happens because it is in someone's ~/.ssh/config, not because anyone decided it was needed. Ship a managed client configuration that sets a secure default and makes ProxyJump a one-word habit.

  • Global default off: a final Host * block with ForwardAgent no. Because ssh_config uses the first value obtained for each parameter, place specific Host blocks above it.
  • Per-zone jump hosts: Host *.prod.example.internal with ProxyJump bastion-prod.example.internal, so engineers type the target name and the tunnel follows. ProxyJump and ProxyCommand compete, and whichever is specified first wins, so remove legacy ProxyCommand lines that call nc.
  • Named exceptions only: where forwarding is approved, enable it only in the Host block for that host, with IdentityAgent pointing at a zone-specific agent loaded with ssh-add -c -t and -h constraints.
  • Pin identities: IdentitiesOnly yes with an explicit IdentityFile per zone stops the client offering every loaded key to every server.
  • Agent hygiene: AddKeysToAgent confirm for interactive keys, a default lifetime on the agent, and ssh-add -D or a locked agent (ssh-add -x) when stepping away.
  • Verify effective settings: ssh -G with the target name prints the resolved configuration, including ForwardAgent and ProxyJump, which is the fastest way to audit what a given connection will actually do.

How to implement: a phased migration

  1. Measure current use: on bastions and intermediate hosts, count sessions that request agent forwarding (sshd logs channel requests at LogLevel VERBOSE) and collect client configs from managed endpoints to find ForwardAgent yes in wildcard blocks.
  2. Classify each use: pure reachability (replace with ProxyJump), remote action needed (replace with a scoped machine credential or keep as a constrained exception), or unknown (contact the owner).
  3. Prepare the bastion: stand up the relay Match block with PermitOpen in parallel with existing access; do not remove shells yet.
  4. Pilot ring: move one team to a managed client config with ProxyJump and ForwardAgent no for two weeks, tracking failed connections and help requests.
  5. Enforce on the bastion: set AllowAgentForwarding no and remove shells for relay users. Roll back by reverting the Match block, which is a single configuration change and an sshd reload; keep the previous file and validate with sshd -t before every reload.
  6. Constrain the exceptions: for each approved forwarding case, document owner, hosts and expiry, and require destination constraints and confirmation.
  7. Close the loop: extend DisableForwarding yes to targets and review exceptions quarterly.

Decision guidance

SituationRecommended approachReason
Reaching a private host through a bastionProxyJumpNo credential exposure on the hop
Git pull or rsync run on a remote build or staging hostScoped deploy key or certificate on that host; constrained forwarding only as a stopgapThe remote action should not borrow a human's full key set
Fleet orchestration host fanning out to many nodesMachine identity with short-lived certificates issued to the orchestratorForwarding a human agent to a busy shared host is the highest-exposure pattern
Hop you do not control (customer, partner, vendor)ProxyJump, never forwardingYou cannot assess who has root there
Hosts on old OpenSSH without ProxyJump or destination-constraint supportProxyCommand with ssh -W through the hop; upgrade plan-W gives the same end-to-end tunnel; constraints need modern versions on every participating host
Single-hop access with no intermediate hostNeither: connect directly with ForwardAgent noForwarding into the destination only adds exposure

Small versus large organisations: a small team with one bastion can get most of the benefit in a day by switching to ProxyJump and turning off agent forwarding on the bastion. Large estates need the managed client configuration, a certificate authority, PermitOpen sets per zone and an exceptions register, because forwarding tends to reappear through personal configs.

Detection and measurement

sshd logs to the AUTH facility; forward it centrally, since local logs on a compromised bastion cannot be trusted. The Linux SSH and Authentication Log Detection Guide covers parsing. Signals specific to this topic:

  • Agent forwarding requests on hosts that should refuse them, and any successful forwarding on relay bastions after enforcement.
  • Non-owner access to agent sockets on intermediate hosts: auditd watches on agent socket directories and process activity by root touching other users' SSH_AUTH_SOCK paths map to T1563.001.
  • Logins on targets from the bastion address with keys whose owner has no open bastion session, or outside that owner's working pattern.
  • Forwarding to destinations outside PermitOpen (refused channel opens), which can indicate reconnaissance through the bastion.
MetricTarget
Share of bastion sessions requesting agent forwardingZero after enforcement
Managed endpoints with ForwardAgent yes in a wildcard Host blockZero
Approved forwarding exceptions with owner, expiry and destination constraints100 percent
Relay bastion users with an interactive shellZero
Bastions with PermitOpen set for every relay group100 percent

Common failure patterns

  • Wildcard forwarding in personal configs: Host * with ForwardAgent yes copied from a blog years ago, forwarding to every server including third-party ones.
  • Disabling agent forwarding but leaving shells: users with a shell can relay the socket with other tools, which is exactly what the sshd_config warning describes; the bastion setting is cosmetic without shell restrictions.
  • ProxyJump through an open relay: no PermitOpen, so any valid key holder can reach any internal port via the bastion.
  • Trusting confirm prompts: approving every askpass popup without reading it, when the popup cannot show the destination anyway.
  • One agent for everything: production, code signing and personal keys loaded into the same agent that gets forwarded to a staging box.
  • Stale known_hosts with destination constraints: constraints resolve host names through known_hosts at load time, so wrong or missing entries either break access or bind the constraint to the wrong key.

Framework mapping

Control objectiveNIST CSF 2.0NIST SP 800-53 Rev 5ISO/IEC 27001:2022 Annex AATT&CK
Restrict how remote administrative access is routedPR.AA-05AC-17, SC-78.20T1021.004
Limit credential exposure on intermediate hostsPR.AA-01IA-5, AC-68.2, 8.5T1563.001
Authenticate users end to endPR.AA-03IA-28.5T1563.001
Control flows through the bastion (PermitOpen)PR.AA-05AC-48.20T1021.004
Managed client and server SSH configurationPR.PS-01AC-178.9T1552.004
Log and monitor forwarding and socket accessDE.CM-03AU-28.15, 8.16T1563.001

Where identity fits

Agent forwarding is an identity problem as much as a network one: a human's credentials end up acting on a host the human does not control, and every automated task built on forwarding is a machine workload borrowing a person's identity. Replacing those tasks with scoped, short-lived machine credentials gives each workload its own auditable identity and removes the reason to forward. The SSH Keys vs SSH Certificates guide covers the credential choice.

Practitioner checklist

  • Set ForwardAgent no as the managed client default and use ProxyJump for every bastion path.
  • Configure relay bastions with no shells, AllowTcpForwarding local, AllowAgentForwarding no, PermitListen none and an explicit PermitOpen per group.
  • Replace automation that relies on a forwarded human agent with scoped machine keys or certificates.
  • For each remaining forwarding exception, record owner and expiry and require ssh-add -h, -c and -t.
  • Run a separate agent per trust zone with IdentityAgent and IdentitiesOnly.
  • Use FIDO keys with user presence for administrative access.
  • Restrict targets to accept SSH only from bastion addresses and set DisableForwarding yes by default.
  • Forward sshd logs centrally and alert on agent forwarding requests and non-owner agent socket access.
  • Audit effective client settings with ssh -G and server settings with sshd -T after each change.

Standards and references

Related NHI Mgmt Group resources: OpenSSH Server Hardening Guide · Securing the jump host and bastion itself · Security Keys for SSH · If your jump host and bastion is compromised · Privileged Access Workstations vs Jump Servers

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 14 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org