Guide

SSH agent forwarding from your phone

SSH agent forwarding lets a server sign with the key on your phone without ever holding it — and lets root on that server act as you. When it's safe, and how.

CC Chen Chen· Founder·2026-09-09·12 min read

The short answer

SSH agent forwarding lets a server you are logged into use the private key that stays on your phone. You turn it on with ssh -A or ForwardAgent yes, the server gets a socket instead of a key, and it can then authenticate onward — to GitHub, to a second server — as you, without any key material ever being written to its disk.

It works from a phone. Blink Shell, Termius, ConnectBot and Termux all implement it, and there is one thing on mobile it is uniquely good for: a key generated inside the Secure Enclave or the Android keystore cannot be copied to a server, so forwarding is the only way to use it from one.

The price is precise, and it is the whole reason this article exists: for as long as that session is open, anyone who can bypass file permissions on that host — root, or any process running as your user — can sign with your key. They cannot steal it. They do not need to. They ask the socket, and the socket answers.

So the rule that survives contact with reality:

  • Off by default. Never Host *, never a global toggle in the app.
  • On per host, per session, for a machine whose root you already are.
  • Never to a bastion, a CI runner, a shared box, or a server you are logging into because you suspect it is compromised.
  • If you only want to reach a second server through a first one, you do not need this at all. That is ProxyJump, and the key never leaves the phone.

What SSH agent forwarding actually does

An agent is a program that holds unlocked private keys and answers exactly one kind of question: here is a challenge, sign it. On a laptop that is ssh-agent. On a phone it is the SSH app itself, backed by the iOS Keychain or the Android Keystore.

When you connect with -A, your client opens an extra channel ([email protected]) inside the encrypted session. sshd on the far side creates a UNIX-domain socket — something like /tmp/ssh-Xf3kQ2/agent.14127 — owned by your user, and sets SSH_AUTH_SOCK in your shell to point at it. Any process that can open that socket can send signature requests back down the tunnel to your phone.

Three consequences follow, and they explain everything else:

  1. No key material crosses. Only challenges and signatures. A compromised server cannot end up holding your private key.
  2. Anyone who can open the socket is you. File permissions are the only guard, and root ignores file permissions. Root can enumerate every /tmp/ssh-* socket on the box, export SSH_AUTH_SOCK, and authenticate to anything your key opens. So can malware running as your own user.
  3. The window is the session. Close the connection and the socket dies. This is why “per session” is a real mitigation rather than security theatre.

The ssh_config manual says this in its own words: agent forwarding should be enabled with caution, because users able to bypass file permissions on the remote host can access the local agent through the forwarded connection — they cannot obtain key material, but they can perform operations on the keys that let them authenticate using your identities. The same paragraph recommends a jump host as the safer alternative.

When it is safe and when it is not

The question is never “is agent forwarding secure” in the abstract. It is: do I trust root on that box, more than I would mind that box signing as me everywhere my key works?

Where you are forwarding toVerdict
A personal VPS or dev box where you are the only rootAcceptable, per session
Your own server, so it can git push as youAcceptable — but a deploy key is better and permanent
A jump host or bastionNo. Use ssh -J; that is what it is for
A CI runner, a Jenkins node, a build agentNo. This is the case that has actually burned people
A client’s server, a shared box, anything with other adminsNo. You are trusting every one of them
A box you are logging into because it is behaving strangelyAbsolutely not. Forwarding into a possible compromise hands over the key

That fourth row is not hypothetical. In the Matrix.org breach of April 2019, an attacker exploited a known Jenkins vulnerability, then planted a script on the Jenkins node that hijacked SSH agent forwarding from anyone who logged in. On 4 April an engineer connected to that node with their agent forwarded, for convenience, to reach other machines. The attacker inherited that access and ended up with superuser reach across much of the production network, including the databases. The published remediation was to stop forwarding agents into that tier and route access through a bastion instead.

One more piece of evidence about the shape of this risk: the recent OpenSSH agent vulnerabilities all have “you forwarded your agent” as their precondition. CVE-2023-38408 (July 2023, affecting OpenSSH 5.5 through 9.3p1) let a malicious server execute code on the client through the forwarded agent. And CVE-2026-73281, fixed in OpenSSH 10.5 on 11 August 2026, was a misinteraction between agent locking and the [email protected] extension: locking the agent switched off the check that distinguishes a local request from one arriving down a forwarded connection, so an attacker holding a forwarded socket could perform operations meant to be local-only — including using keys that carried destination restrictions. Ubuntu shipped the fix in USN-8721-1 on 3 September 2026. Do not forward, and none of these reach you.

What changes when the agent is a phone

Everything above is true on a laptop too. Five things are specific to doing it from a handset, and two of them are genuinely in mobile’s favour.

1. The agent is an app, and apps get suspended. Your phone is now a service the server depends on. If iOS suspends the SSH app — Termius documents that recent iOS and iPadOS versions stop an app’s background processes in roughly 20 to 30 seconds — the agent stops answering. A git clone on the server that needs a signature mid-operation will simply hang and then fail. Anything long-running belongs in tmux on the server, and anything that needs your agent should finish while you are looking at the screen.

2. Not every client can do it. Agent forwarding requires the app to implement an agent and the auth-agent channel. Plenty of mobile SSH clients do public-key authentication and nothing more; there is no setting to find, because the machinery is not there.

3. Biometric keys turn the risk into an alarm. This is the good part. If your key is gated by Face ID or a fingerprint per signature, then a hijacked socket cannot be used silently — the attacker’s request surfaces as a prompt on a phone in your pocket that you did not trigger. That is the mobile-native version of ssh-add -c, and it is stronger than anything a laptop offers by default. Treat an unexplained authentication prompt as an incident, not an annoyance: decline it and kill the session.

4. Forwarding is the only way to use a hardware-backed mobile key remotely. A Secure Enclave key is ecdsa-sha2-nistp256 and non-extractable by hardware design (the full explanation). You cannot scp it to a server, which is the point. If you want a server to act with that key — signing commits, for instance — forwarding is the mechanism. That is the strongest legitimate reason to use it from a phone.

5. You get the app’s controls, not OpenSSH’s. ssh-add -c, -t and -h are OpenSSH features. A GUI client gives you whatever toggles it chose to build, which is usually one on/off switch per host. If you need real constraints, you need a client with a command line.

How to forward your agent from a phone

ClientPlatformAgent forwardingHow
Blink ShelliOS / iPadOSYesReal OpenSSH-style flags: ssh -A host, or ForwardAgent yes in the host’s SSHConfig field (docs)
TermiusiOS / Android / desktopYesUses its own built-in agent rather than the OS agent; agent forwarding is a per-host setting (docs)
ConnectBotAndroidYesLong-press host → Edit host → Use SSH auth agent: No / Yes / With confirmation (issue #378)
TermuxAndroidYesIt is actual OpenSSH — ssh-agent, ssh-add -c/-t/-h, ssh -A, all exactly as documented
TermAIiOS / AndroidYesListed among the supported auth methods on the features page; keys stay in the iOS Keychain / Android Keystore

ConnectBot’s three-state setting deserves the attention. With confirmation is the correct choice and it is rare in mobile clients — every signature request raises a prompt, which means a compromised server gets one visible attempt rather than unlimited silent ones. If you are choosing an Android client for this specific job, that setting is a reason to pick it; the wider comparison is in ConnectBot alternatives.

In a client with a real config file, the shape you want is per host and nothing wider:

Host devbox
    HostName devbox.example.com
    User chen
    IdentityFile ~/.ssh/id_ed25519_phone
    IdentitiesOnly yes
    ForwardAgent yes          # this host only

Host bastion
    HostName bastion.example.com
    ForwardAgent no           # explicit, so no future edit turns it on

Host prod-*
    ProxyJump bastion         # jump, do not forward
    ForwardAgent no

IdentitiesOnly yes matters more on a phone than on a laptop, because mobile clients tend to accumulate keys and offer all of them — which is how you meet too many authentication failures.

On the server side, forwarding must also be permitted where you land. AllowAgentForwarding in sshd_config defaults to yes, and per-key options in authorized_keys can override it: no-agent-forwarding, or restrict, which disables agent forwarding, port forwarding, X11 and pty allocation in one word since OpenSSH 7.2 (29 February 2016). Note the direction: those settings control whether other people can forward agents into your box. They do nothing to protect your own key on a host someone else runs.

Six settings that make it defensible

If you have decided a particular hop justifies forwarding, these are the controls worth applying, roughly in order of value per unit of effort.

1. Per host, never Host *. A global ForwardAgent yes means every server you touch — including one you connect to once, from a link, in a hurry — gets a live signing oracle. This single line is the most common way people get the Matrix outcome.

2. Require confirmation for every use. On OpenSSH, ssh-add -c ~/.ssh/id_ed25519 makes the agent ask before each signature. In ConnectBot, that is the With confirmation value. On a phone with a biometric-gated key, you get it for free. This converts a silent compromise into a visible one.

3. Give the key a lifetime. ssh-add -t 30m makes the agent forget the key after thirty minutes, so a forgotten session does not stay signable all afternoon.

4. Constrain the destination. OpenSSH 8.9 (23 February 2022) added destination-constrained keys, documented at openssh.com/agent-restrict.html:

ssh-add -h "bastion.example.com>prod-web.internal" ~/.ssh/id_ed25519

The client sends a [email protected] message on every hop, cryptographically tying the session to the host key it authenticated, so the agent can reconstruct the path a request travelled and refuse anything off the declared route. A key stolen through a forwarded socket then only works on the one destination you named. The catch: every ssh in the chain must be new enough to send the binding, which in practice means Termux or a desktop, not a GUI mobile client.

5. Forward a smaller agent, not your whole keyring. Since OpenSSH 8.2 (14 February 2020), ForwardAgent accepts an explicit socket path or the name of an environment variable, not just yes/no. Run a second agent holding only the one key that hop needs, and forward that. What is exposed is then one credential rather than every key you own.

6. Patch the agent. The agent is the component the CVEs land in — CVE-2023-38408 and CVE-2026-73281 both required a forwarded socket to exploit. Worth saying plainly: those are OpenSSH bugs, and a mobile app that implements its own agent is running its own, much less audited code. That is not a reassurance.

The alternatives that are usually better

Most requests for agent forwarding are really requests for something else. Check this list before enabling it.

What you actually wantBetter toolWhy
Reach server B through bastion Assh -J bastion BAuthentication happens on the phone; A relays ciphertext and can do nothing with it
Let a dev box pull and push one repoDeploy key on that repoRead-only by default, scoped to one repo, survives your phone being asleep
Let a shared box use GitMachine user with its own accountProper isolation and its own audit trail
Reach a private host directlyTailscaleThe second hop stops existing; there is nothing to jump through (setup)
Run one command on a second hostssh -J a b 'systemctl status nginx'No interactive session on the middle box at all
Sign commits made on the serverForwarded Secure Enclave key — the real use caseThe key cannot be copied there; forwarding is the only route

ProxyJump is the substitution that covers most of the traffic. ssh -J bastion prod-web opens a direct-tcpip channel through the bastion and then performs a fresh key exchange and authentication with the final host, inside that channel — so the bastion sees encrypted bytes, never a signing socket, and never needs to give you a shell. Two host keys get verified rather than one, which is why a first connection from a phone prompts twice (host keys and TOFU).

The Git case is worth spelling out because it is the one people arrive here for: if a box needs to talk to GitHub, a deploy key (read-only by default, scoped to one repository) beats a forwarded agent on every axis except setup time, and it keeps working when your phone is in a drawer. The full decision — deploy key, user key, machine user, or forwarding — is in Git from your phone over SSH.

And the mobile-specific version: with a mesh network on the phone, reaching the target directly usually removes the middle host from the picture entirely. There is no agent to forward when there is no hop. This is why TermAI embeds Tailscale rather than treating the bastion chain as the normal case — the safest forwarded agent is the one you never needed. The rest of the mobile threat model is in is mobile SSH safe for production.

Checking and troubleshooting

First, verify from the remote host that forwarding actually happened:

echo $SSH_AUTH_SOCK          # empty means no agent was forwarded
ssh-add -l                   # lists the keys your phone is offering

ssh-add -l printing your key fingerprint means the chain works end to end. It also means anyone else on that box can run the same command, which is a useful thing to see once.

SymptomCauseFix
Could not open a connection to your authentication agentNothing was forwardedClient did not send -A; or the host’s sshd has AllowAgentForwarding no; or the key carries restrict / no-agent-forwarding
SSH_AUTH_SOCK set, but ssh-add -l says The agent has no identitiesThe socket reached the host; the phone’s agent is empty or lockedUnlock the app, or load the key into it
Works in ssh, fails in scp or sftpDeliberate: those tools do not forward by defaultPass -A explicitly (OpenSSH 8.4, 27 September 2020)
Works as your user, fails under sudosudo resets the environment and drops SSH_AUTH_SOCKsudo -E, or do the SSH part as your own user
Agent admitted failure to signThe requested key is not in the agent, or a destination constraint refused itssh-add -l to confirm; check the -h path you declared
Everything hangs after you switch appsThe phone suspended the agentKeep the app foregrounded for anything that needs a signature
A Face ID prompt you did not triggerSomething on the remote host is using your socketDecline, disconnect, treat as an incident

If the connection itself is not establishing, the problem is upstream of any of this — start at Permission denied (publickey) or, in the worse case, getting back into a server you are locked out of.

FAQ

What is SSH agent forwarding? A client feature, enabled with ssh -A or ForwardAgent yes, that lets a server you are logged into ask your local machine to sign authentication challenges with your private key. The server never receives the key. sshd creates a UNIX-domain socket on the remote host and points SSH_AUTH_SOCK at it; anything that can talk to that socket can request a signature. That is how you authenticate onward from that server to a third host without storing a key on the middle one. On a phone, the agent is the SSH app, and the key stays in the iOS Keychain, the Secure Enclave, or the Android Keystore.

Is SSH agent forwarding safe? It is safe exactly to the degree that you trust root on the host you forward to, for as long as the session is open. The OpenSSH manual states the risk plainly: users who can bypass file permissions on the remote host can reach your forwarded agent, and while they cannot extract the key, they can perform operations with it — so they can authenticate as you anywhere that key is accepted. In the April 2019 Matrix.org breach, an attacker who controlled a Jenkins host ran a script that hijacked the forwarded agent of any engineer who logged in, and used it to reach production.

Can I use ssh -A from an iPhone or Android phone? Yes, in clients that implement an agent. Blink Shell on iOS supports agent forwarding and lets you set ForwardAgent per host through its SSHConfig field. Termius uses its own built-in agent rather than the OS agent and exposes agent forwarding as a per-host setting. ConnectBot on Android has a Use SSH auth agent option in each host’s settings with three values — No, Yes, and With confirmation. Termux runs real OpenSSH, so ssh-agent, ssh-add and every documented flag behave exactly as they do on a desktop.

Why would I forward an agent from a phone at all? Because a mobile SSH key is usually non-extractable by design. A key generated in the Secure Enclave or the Android keystore cannot be copied to a server, so forwarding is the only mechanism that makes it usable from one — to git push from a development box, or to sign commits there with a key that Face ID guards. If your goal is only to reach a second server through a first, you do not need forwarding: ProxyJump does that with the key never leaving the phone.

What is the difference between agent forwarding and ProxyJump? Where the authentication happens. With agent forwarding you log into the jump host and run ssh from there, so that host holds a live socket that can sign with your key. With ssh -J the jump host only relays an encrypted channel; key exchange and authentication with the final host happen on your phone, end to end, and the middle box can read nothing. A compromised jump host can impersonate you in the first case and can do nothing in the second.

How do I make agent forwarding less dangerous? Enable it per host rather than in a Host * block. Require confirmation for every signature — ssh-add -c, ConnectBot’s With confirmation, or a biometric-gated key, so an unexpected prompt becomes your intrusion alarm. Give keys a lifetime with ssh-add -t. Add destination constraints with ssh-add -h, introduced in OpenSSH 8.9 on 23 February 2022, to bind a key to a specific chain of hosts. And keep the agent patched: OpenSSH 10.5, released 11 August 2026, fixed CVE-2026-73281, where a locked agent could be driven from the far end of a forwarded connection.

Does agent forwarding work with scp and sftp? Not by default, even when your ssh_config enables it. OpenSSH 8.4, released 27 September 2020, added an explicit -A flag to scp and sftp precisely because those tools deliberately do not forward the agent unless asked on the command line. If a transfer from an intermediate host fails to authenticate while an interactive session from the same host works, this asymmetry is usually why.

Quick facts

  • ssh -A forwards the agent; -a disables it; ForwardAgent defaults to no. Keep it that way and set it per host.
  • No key material crosses. A socket appears on the remote host and SSH_AUTH_SOCK points at it; requests travel back to the phone for signing.
  • Root on that host, or any process running as you, can use the socket for the life of the session. They cannot extract the key and do not need to.
  • Matrix.org, April 2019: a compromised Jenkins node hijacked forwarded agents from engineers who logged in, leading to superuser access across production.
  • Recent agent CVEs need a forwarded agent: CVE-2023-38408 (July 2023, OpenSSH 5.5–9.3p1) and CVE-2026-73281 (fixed in OpenSSH 10.5, 11 August 2026).
  • Mobile clients that support it: Blink Shell (iOS), Termius (iOS/Android, own built-in agent), ConnectBot (Android, with a With confirmation mode), Termux (real OpenSSH), TermAI.
  • A biometric-gated key is the best confirmation prompt available — an unexpected Face ID request is an intrusion alarm.
  • A suspended app is a dead agent. iOS stops background processes in roughly 20–30 seconds; signature requests then hang.
  • Destination constraints (ssh-add -h, OpenSSH 8.9, 23 February 2022) bind a key to a named host chain, but every hop’s ssh must support the binding extension.
  • scp and sftp never forward by default — pass -A explicitly (OpenSSH 8.4+).
  • If you only need to reach a host behind a bastion, use ssh -J. If you control both ends, a mesh network removes the hop entirely.
Try TermAI

Free on iOS and Android. 5 AI requests/day on the free tier, plus unlimited SSH/SFTP and built-in Tailscale.

CC
Chen Chen — Founder of TermAI

Writes about mobile DevOps, terminal UX, and the surprising depth of "boring" infrastructure.