<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Agent · XB Field Notes</title><link>https://hk.xbcatm.com/tags/agent/</link><description>Illustrated field notes on HTTP, DNS, TLS, Caddy, SSH, releases, and recovery.</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://hk.xbcatm.com/tags/agent/index.xml" rel="self" type="application/rss+xml"/><item><title>Forwarding an SSH agent</title><link>https://hk.xbcatm.com/posts/linux-ssh-agent-forwarding/</link><pubDate>Wed, 09 Feb 2028 00:00:00 +0000</pubDate><guid>https://hk.xbcatm.com/posts/linux-ssh-agent-forwarding/</guid><description>Agent forwarding keeps private key material local, but lets a remote host request authentication signatures.</description><content:encoded>&lt;p&gt;Agent forwarding is not the agent itself. A local agent can answer authentication requests without sending the private key to the server. Forwarding additionally makes that service reachable through a socket on a remote host. Keeping key material local therefore does not mean keeping its authentication capability local.&lt;/p&gt;
&lt;p&gt;That distinction matters when choosing a route through a bastion. If the task is simply to log into a private machine, use &lt;code&gt;ProxyJump&lt;/code&gt; with forwarding disabled. Forwarding is useful when a program actually running on the remote machine needs your agent, such as a deliberately authorized second SSH connection.&lt;/p&gt;
&lt;h2 id="the-remote-gets-a-capability"&gt;The remote gets a capability&lt;/h2&gt;
&lt;p&gt;The forwarded socket is normally exposed through &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt;. Processes with access to it, including a sufficiently privileged attacker on that host, can request operations from the originating agent. This is not permission for every unrelated account on the machine, and it is not an export of the private key.&lt;/p&gt;
&lt;p&gt;An unconstrained loaded identity can nevertheless authorize unwanted logins while the forwarding channel remains available. Key lifetime, confirmation requirements, destination restrictions, and server authorization all affect what succeeds. Calling this unrestricted ownership of the key overstates the mechanism, but understating socket access is just as dangerous.&lt;/p&gt;
&lt;p&gt;An earlier version cited an unexplained 88-byte signature as evidence. Signature length alone establishes neither the OpenSSH agent protocol nor a forwarded authentication exchange. The exercise below instead tests a narrow, observable property with the actual client: its effective forwarding configuration.&lt;/p&gt;
&lt;h2 id="forwarding-follows-effective-configuration"&gt;Forwarding follows effective configuration&lt;/h2&gt;
&lt;p&gt;Omitting &lt;code&gt;-A&lt;/code&gt; does not turn forwarding off. A matching &lt;code&gt;Host&lt;/code&gt; block, an included configuration file, or system configuration can already enable it. Conversely, &lt;code&gt;-A&lt;/code&gt; explicitly enables forwarding even when a configuration file says &lt;code&gt;ForwardAgent no&lt;/code&gt;. Use &lt;code&gt;-a&lt;/code&gt; or an unambiguous &lt;code&gt;-o ForwardAgent=no&lt;/code&gt; when disabling it for a connection.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ProxyJump&lt;/code&gt; supplies a TCP route to the destination; it does not reset the destination&amp;rsquo;s forwarding option. The target SSH connection and its authentication still originate locally, so ordinary jump access needs no forwarded agent. Inspect settings for the destination and jump hosts separately, because their configuration is not necessarily identical.&lt;/p&gt;
&lt;p&gt;On a remote shell, a subsequent SSH client evaluates its own configuration. Count effective settings, not appearances of &lt;code&gt;-A&lt;/code&gt; in command history. Also check connection multiplexing when diagnosing an existing session: printing configuration describes a proposed invocation, not every property of a previously established connection.&lt;/p&gt;
&lt;h2 id="limit-the-delegation"&gt;Limit the delegation&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ssh-add -c&lt;/code&gt; requests confirmation through an askpass program; absence of a terminal alone does not explain whether approval works. &lt;code&gt;ssh-add -t&lt;/code&gt; limits an identity&amp;rsquo;s lifetime. Destination constraints, available since OpenSSH 8.9, use known host keys and require cooperating client and server support along forwarded paths. Every cooperating hop must be allowed. A hostile hop can relay the socket again using other tools, while signing remains restricted to permitted destinations.&lt;/p&gt;
&lt;p&gt;Server-side &lt;code&gt;AllowAgentForwarding no&lt;/code&gt; disables OpenSSH&amp;rsquo;s built-in facility. It does not prevent a user with unrestricted shell access from arranging another forwarder. Keep that restriction, but do not mistake it for isolation from a hostile shell user.&lt;/p&gt;
&lt;h2 id="when-it-breaks"&gt;When it breaks&lt;/h2&gt;
&lt;p&gt;A compromised bastion can misuse an accessible forwarded agent while the channel and relevant identity remain usable. Replacing the private-key file on disk does not unload the agent&amp;rsquo;s old identity. Respond by ending the forwarding connection and removing the affected loaded identity; revoke the corresponding server authorization if compromise warrants it. Already established remote sessions need separate handling.&lt;/p&gt;
&lt;p&gt;Another failure is enabling forwarding in &lt;code&gt;Host *&lt;/code&gt; and forgetting it. Prefer narrow host exceptions and an agent containing only the needed identities. Selecting &lt;code&gt;IdentityFile&lt;/code&gt; for one login is not a filter over everything a forwarded agent exposes.&lt;/p&gt;
&lt;figure class="technical-diagram"&gt;
&lt;img loading="lazy" src="https://hk.xbcatm.com/visuals/posts-linux-ssh-agent-forwarding.detail.en.svg" alt="A route ladder is separate from a two-way local-agent and remote-socket capability diagram; four retained effective-configuration rows show no, yes, yes, no before destination and relay limits." width="560" height="3080"&gt;
&lt;figcaption&gt;ProxyJump supplies a route; forwarding exposes signing capability. Effective configuration and cooperating destination restrictions need separate checks.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="check-it-quickly"&gt;Check it quickly&lt;/h2&gt;
&lt;p&gt;This disposable configuration prints four settings for manual comparison; it opens no network connection or private key. It has no value assertions or failure/cleanup trap:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Host *\n ForwardAgent no\n&amp;#39;&lt;/span&gt; &amp;gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh -G -F &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; target.invalid &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s1"&gt;&amp;#39;^forwardagent &amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh -G -F &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -A target.invalid &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s1"&gt;&amp;#39;^forwardagent &amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Host *\n ForwardAgent yes\n&amp;#39;&lt;/span&gt; &amp;gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh -G -F &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -J bastion.invalid target.invalid &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s1"&gt;&amp;#39;^forwardagent &amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh -G -F &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -a -J bastion.invalid target.invalid &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s1"&gt;&amp;#39;^forwardagent &amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The retained OpenSSH 10.0p2 record reports no, yes, yes, no; this review did not rerun it. This verifies option handling, not socket permissions, signing, destination constraints, or a live multi-hop connection. For a trusted real configuration, inspect &lt;code&gt;ssh -G destination&lt;/code&gt; and jump-host aliases; evaluating Match exec can run local commands and hostname canonicalization can invoke DNS. A forwarding value of yes should have a specific reason and a trusted recipient.&lt;/p&gt;
&lt;h2 id="sources"&gt;Sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://man.openbsd.org/ssh.1"&gt;OpenBSD: ssh&lt;/a&gt;, command-line forwarding controls, jump connections, and configuration inspection, checked 2026-10-15.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man.openbsd.org/ssh_config.5"&gt;OpenBSD: ssh_config&lt;/a&gt;, ForwardAgent, ProxyJump, and configuration precedence, checked 2026-10-15.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man.openbsd.org/ssh-agent.1"&gt;OpenBSD: ssh-agent&lt;/a&gt;, agent sockets and authentication without transferring private keys, checked 2026-10-15.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man.openbsd.org/ssh-add.1"&gt;OpenBSD: ssh-add&lt;/a&gt;, askpass confirmation, lifetimes, and destination-constraint requirements, checked 2026-10-15.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man.openbsd.org/sshd_config.5"&gt;OpenBSD: sshd_config&lt;/a&gt;, AllowAgentForwarding and the shell-access limitation, checked 2026-10-15.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item></channel></rss>