RubySec

Providing security resources for the Ruby community

GHSA-qpg5-fx6p-8cq3 (net-ssh): Using port forwarding silently enables server access to the local SSH agent

Using port forwarding silently enables server access to the local SSH agent

Published: October 05, 2026

SECURITY IDENTIFIERS

GEM

net-ssh

SEVERITY

CVSS v3.x: 8.0 (High)

PATCHED VERSIONS

~> 7.3, >= 7.3.5 >= 8.0.0.rc2

DESCRIPTION

Improper authorization in net-ssh: Service::Forward#initialize registers server-initiated auth-agent channel handlers unconditionally, so ordinary port forwarding exposes the local SSH agent

Summary

Net::SSH::Service::Forward#initialize registers channel handlers for the server-initiated channel types auth-agent and auth-agent@openssh.com at the moment the forwarding service is instantiated, alongside the expected forwarded-tcpip handler. Nothing in that registration, and nothing in auth_agent_channel itself, consults options[:forward_agent] or the service's own @agent_forwarded flag. A consumer that uses ordinary TCP or UNIX-socket forwarding with the default forward_agent: false therefore still accepts an auth-agent@openssh.com channel opened by the remote server, connects to the local SSH agent, and relays raw agent protocol to that server.

In a realistic consuming application, the attacker is the SSH server (malicious or compromised): it controls the channel_type of the CHANNEL_OPEN packets it sends, and Connection::Session#channel_open dispatches any channel type that has a registered handler. No prior auth-agent-req from the client is required, and no client code ever asked for agent forwarding.

Related paths, for contrast:

  • Client-side opt-in guard in Channel#do_open_confirmation — checks connection.options[:forward_agent] before the client sends an enable request (lib/net/ssh/channel.rb:534).

  • The vulnerable path: incoming auth-agent / auth-agent@openssh.com handlers registered independently of that guard — unguarded, lib/net/ssh/service/forward.rb:25-35.

  • A client that never instantiates the forwarding service — the same server request is refused with CHANNEL_OPEN_FAILURE code 3, "unknown channel type auth-agent@openssh.com" (observed in the verification negative control).

The documented design intent is that agent forwarding is an explicit opt-in: lib/net/ssh/service/forward.rb:277-289 states that agent forwarding is enabled when the connection was created with :forward_agent => true, while the README documents ssh.forward.local independently. Port forwarding is not documented as authorizing agent forwarding.

Impact

A malicious or compromised SSH server gains a live relay to the client's local ssh-agent. It can enumerate the victim's loaded identities and request signatures over attacker-chosen data, which lets it authenticate onward to other hosts as the victim — using keys the victim's application never intended to expose to that server. This happens while the application's configuration says agent forwarding is off.

The delta versus safe behaviour: with forward_agent false and no forwarding service instantiated, a server that opens an auth-agent@openssh.com channel gets CHANNEL_OPEN_FAILURE and never touches the agent. Merely calling ssh.forward.local (or another forwarding API) converts that refusal into a working agent relay. Port forwarding and agent forwarding are separate capabilities in the SSH ecosystem and in this library's own documentation; this collapses the second into the first.

RELATED