[crypto] ssh: enforce source-address critical option for all auth methods

2 views
Skip to first unread message

Gerrit Bot (Gerrit)

unread,
Jun 6, 2026, 1:21:16 PM (12 hours ago) Jun 6
to goph...@pubsubhelper.golang.org, Alan, golang-co...@googlegroups.com

Gerrit Bot has uploaded the change for review

Commit message

ssh: enforce source-address critical option for all auth methods

CVE-2026-46595 (CL 781642) added the `source-address` critical-option check to the publickey path's `VerifiedPublicKeyCallback` branch in `userAuthLoop`. The other auth methods that return `*Permissions` — `none` (NoClientAuthCallback), `password` (PasswordCallback), `keyboard-interactive` (KeyboardInteractiveCallback) and `gssapi-with-mic` — still return their `Permissions` to the caller without validating the remote address against `CriticalOptions["source-address"]`.

The `Permissions` struct documentation states the package enforces the `source-address` critical option, with no caveat that this is limited to publickey. A server that sets the restriction from any non-publickey callback (password auth scoped to a corporate range, keyboard-interactive 2FA, GSSAPI SSO, or break-glass none auth) currently gets no enforcement and no warning.

This moves the enforcement to a single check after the auth-method switch so it applies uniformly to every method. The existing publickey-path checks are left in place as defense in depth.

A regression test (`TestSourceAddressCriticalOptionNonPublicKey`) covers the none/password/keyboard-interactive methods; it fails on master and passes with this change. The existing publickey control (`TestVerifiedPubKeyCallbackSourceAddress`) continues to pass.
Change-Id: Ib103ef07f25532cc4d4e9564a205b5e4c08928b0
GitHub-Last-Rev: 798f67cc54cfa778b6182571092550e0d79628b7
GitHub-Pull-Request: golang/crypto#354

Change diff

diff --git a/ssh/server.go b/ssh/server.go
index 0192a67..31310ed 100644
--- a/ssh/server.go
+++ b/ssh/server.go
@@ -896,6 +896,20 @@
authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method)
}

+ // Enforce the "source-address" critical option for every auth
+ // method. CVE-2026-46595 added this check to the publickey path's
+ // VerifiedPublicKeyCallback branch, but the other callback-returning
+ // methods ("none", "password", "keyboard-interactive" and
+ // "gssapi-with-mic") returned their Permissions to the caller without
+ // validating the remote address against the restriction.
+ if authErr == nil && perms != nil && perms.CriticalOptions != nil {
+ if saco := perms.CriticalOptions[sourceAddressCriticalOption]; saco != "" {
+ if err := checkSourceAddress(s.RemoteAddr(), saco); err != nil {
+ authErr = err
+ }
+ }
+ }
+
authErrs = append(authErrs, authErr)

if config.AuthLogCallback != nil {
diff --git a/ssh/server_test.go b/ssh/server_test.go
index 502a25b..4cebbbd 100644
--- a/ssh/server_test.go
+++ b/ssh/server_test.go
@@ -714,6 +714,80 @@
}
}

+func TestSourceAddressCriticalOptionNonPublicKey(t *testing.T) {
+ // CVE-2026-46595 added source-address enforcement to the publickey
+ // path. The same critical option must also be enforced for the other
+ // auth methods that hand back *Permissions. Each callback below
+ // restricts access to 192.168.99.99, which never matches the loopback
+ // address used by netPipe, so every authentication must be rejected.
+ const mismatchingSourceAddr = "192.168.99.99"
+ restrictedPerms := func() (*Permissions, error) {
+ return &Permissions{
+ CriticalOptions: map[string]string{
+ sourceAddressCriticalOption: mismatchingSourceAddr,
+ },
+ }, nil
+ }
+
+ for _, tt := range []struct {
+ name string
+ serverConf *ServerConfig
+ auth []AuthMethod
+ }{
+ {
+ name: "none",
+ serverConf: &ServerConfig{
+ NoClientAuth: true,
+ NoClientAuthCallback: func(ConnMetadata) (*Permissions, error) {
+ return restrictedPerms()
+ },
+ },
+ auth: nil,
+ },
+ {
+ name: "password",
+ serverConf: &ServerConfig{
+ PasswordCallback: func(ConnMetadata, []byte) (*Permissions, error) {
+ return restrictedPerms()
+ },
+ },
+ auth: []AuthMethod{Password("password")},
+ },
+ {
+ name: "keyboard-interactive",
+ serverConf: &ServerConfig{
+ KeyboardInteractiveCallback: func(ConnMetadata, KeyboardInteractiveChallenge) (*Permissions, error) {
+ return restrictedPerms()
+ },
+ },
+ auth: []AuthMethod{KeyboardInteractive(func(string, string, []string, []bool) ([]string, error) {
+ return nil, nil
+ })},
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ c1, c2, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+ defer c1.Close()
+ defer c2.Close()
+
+ tt.serverConf.AddHostKey(testSigners["rsa"])
+ go NewServerConn(c1, tt.serverConf)
+
+ clientConf := &ClientConfig{
+ User: "user",
+ Auth: tt.auth,
+ HostKeyCallback: InsecureIgnoreHostKey(),
+ }
+ if _, _, _, err := NewClientConn(c2, "", clientConf); err == nil {
+ t.Fatalf("client login succeeded via %s auth with a callback returning a mismatching source-address", tt.name)
+ }
+ })
+ }
+}
+
func TestVerifiedPublicCallbackPartialSuccessBadUsage(t *testing.T) {
c1, c2, err := netPipe()
if err != nil {

Change information

Files:
  • M ssh/server.go
  • M ssh/server_test.go
Change size: M
Delta: 2 files changed, 88 insertions(+), 0 deletions(-)
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newchange
Gerrit-Project: crypto
Gerrit-Branch: master
Gerrit-Change-Id: Ib103ef07f25532cc4d4e9564a205b5e4c08928b0
Gerrit-Change-Number: 787860
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-CC: Alan <alanort...@gmail.com>
unsatisfied_requirement
satisfied_requirement
open
diffy

Gopher Robot (Gerrit)

unread,
Jun 6, 2026, 1:21:19 PM (12 hours ago) Jun 6
to Alan, Gerrit Bot, goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

Gopher Robot added 1 comment

Patchset-level comments
File-level comment, Patchset 1 (Latest):
Gopher Robot . unresolved

I spotted some possible problems with your PR:

  1. You have a long 474 character line in the commit message body. Please add line breaks to long lines that should be wrapped. Lines in the commit message body should be wrapped at ~76 characters unless needed for things like URLs or tables. (Note: GitHub might render long lines as soft-wrapped, so double-check in the Gerrit commit message shown above.)
2. You usually need to reference a bug number for all but trivial or cosmetic fixes. For the crypto repo, the format is usually 'Fixes golang/go#12345' or 'Updates golang/go#12345' at the end of the commit message. Should you have a bug reference?

Please address any problems by updating the GitHub PR.

When complete, mark this comment as 'Done' and click the [blue 'Reply' button](https://go.dev/wiki/GerritBot#i-left-a-reply-to-a-comment-in-gerrit-but-no-one-but-me-can-see-it) above. These findings are based on heuristics; if a finding does not apply, briefly reply here saying so.

To update the commit title or commit message body shown here in Gerrit, you must edit the GitHub PR title and PR description (the first comment) in the GitHub web interface using the 'Edit' button or 'Edit' menu entry there. Note: pushing a new commit to the PR will not automatically update the commit message used by Gerrit.

For more details, see:

(In general for Gerrit code reviews, the change author is expected to [log in to Gerrit](https://go-review.googlesource.com/login/) with a Gmail or other Google account and then close out each piece of feedback by marking it as 'Done' if implemented as suggested or otherwise reply to each review comment. See the [Review](https://go.dev/doc/contribute#review) section of the Contributing Guide for details.)

Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement is not satisfiedTryBots-Pass
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: crypto
    Gerrit-Branch: master
    Gerrit-Change-Id: Ib103ef07f25532cc4d4e9564a205b5e4c08928b0
    Gerrit-Change-Number: 787860
    Gerrit-PatchSet: 1
    Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
    Gerrit-CC: Alan <alanort...@gmail.com>
    Gerrit-CC: Gopher Robot <go...@golang.org>
    Gerrit-Comment-Date: Sat, 06 Jun 2026 17:21:14 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    unsatisfied_requirement
    open
    diffy

    Gerrit Bot (Gerrit)

    unread,
    Jun 6, 2026, 1:34:00 PM (12 hours ago) Jun 6
    to Alan, goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
    Attention needed from Nicola Murino

    Gerrit Bot uploaded new patchset

    Gerrit Bot uploaded patch set #2 to this change.
    Open in Gerrit

    Related details

    Attention is currently required from:
    • Nicola Murino
    Submit Requirements:
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement is not satisfiedTryBots-Pass
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: newpatchset
    Gerrit-Project: crypto
    Gerrit-Branch: master
    Gerrit-Change-Id: Ib103ef07f25532cc4d4e9564a205b5e4c08928b0
    Gerrit-Change-Number: 787860
    Gerrit-PatchSet: 2
    Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
    Gerrit-Reviewer: Nicola Murino <nicola...@gmail.com>
    Gerrit-CC: Alan <alanort...@gmail.com>
    Gerrit-CC: Filippo Valsorda <fil...@golang.org>
    Gerrit-CC: Gopher Robot <go...@golang.org>
    Gerrit-CC: Roland Shoemaker <rol...@golang.org>
    Gerrit-Attention: Nicola Murino <nicola...@gmail.com>
    unsatisfied_requirement
    open
    diffy

    Gerrit Bot (Gerrit)

    unread,
    Jun 6, 2026, 1:46:35 PM (12 hours ago) Jun 6
    to Alan, goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
    Attention needed from Nicola Murino

    Gerrit Bot uploaded new patchset

    Gerrit Bot uploaded patch set #3 to this change.
    Open in Gerrit

    Related details

    Attention is currently required from:
    • Nicola Murino
    Submit Requirements:
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement is not satisfiedTryBots-Pass
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: newpatchset
    Gerrit-Project: crypto
    Gerrit-Branch: master
    Gerrit-Change-Id: Ib103ef07f25532cc4d4e9564a205b5e4c08928b0
    Gerrit-Change-Number: 787860
    Gerrit-PatchSet: 3
    unsatisfied_requirement
    open
    diffy
    Reply all
    Reply to author
    Forward
    0 new messages