1- From e9da9a48632aecf8d45a351274dc2f36269140c2 Mon Sep 17 00:00:00 2001
1+ From e3d1254f1e7e60baa086142c46174bf6d8d0fe50 Mon Sep 17 00:00:00 2001
22From: Nicola <nicola.murino@gmail.com>
3- Date: Tue, 27 Jan 2026 12:15:18 +0100
4- Subject: [PATCH] ssh/agent: preserve constraint extensions when adding keys
3+ Date: Sun, 1 Feb 2026 14:55:12 +0100
4+ Subject: [PATCH] ssh/agent: don't accept keys with unsupported constraints
55
6- The client Add method only serialized the lifetime and confirm
7- constraints and silently dropped AddedKey.ConstraintExtensions before
8- sending the SSH_AGENTC_ADD_IDENTITY request. As a result the remote
9- agent always received the key with no extension constraints, regardless
10- of what the caller requested .
6+ The in-memory keyring cannot enforce constraint extensions, so silently
7+ accepting a key that carries them gave callers a false sense of
8+ restriction. Refuse keys with constraint extensions instead: a key
9+ whose constraints cannot be enforced must not be loaded. This behavior
10+ is consistent with OpenSSH .
1111
12- Applications that add a key believing custom constraint extensions
13- (such as restrict-destination-v00@openssh.com) would be enforced
14- instead loaded a completely unrestricted key into the agent. For
15- example, an administrator forwarding their agent into an untrusted jump
16- host and trying to limit the forwarded key with restrict-destination
17- never had that restriction reach the agent: any user or compromised
18- process on that host could make the agent sign arbitrary challenges.
19-
20- Serialize each entry in key.ConstraintExtensions as an
21- agentConstrainExtension constraint so the constraints reach the agent,
22- and add a round-trip regression test that verifies the extensions
23- survive client serialization and server parsing.
12+ This is a deliberate behavior change: keyring.Add previously accepted
13+ and ignored ConstraintExtensions and now returns an error.
2414
2515This issue was found during a security audit by NCC Group Cryptography
2616Services, sponsored by Teleport.
2717
28- Updates CVE-2026-39832
29- Updates golang/go#79435
18+ Fixes CVE-2026-39832
19+ Fixes golang/go#79435
3020
31- Change-Id: I14c5583b106cbf0d282d2ba01e000e0f586f08c7
32- Reviewed-on: https://go-review.googlesource.com/c/crypto/+/778640
21+ Change-Id: I6ca4f1c29f8edfabb287fe07299641f70896d5fe
22+ Reviewed-on: https://go-review.googlesource.com/c/crypto/+/778641
23+ Auto-Submit: Neal Patel <nealpatel@google.com>
24+ LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
3325Reviewed-by: Neal Patel <neal@golang.org>
26+ Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
3427Reviewed-by: Neal Patel <nealpatel@google.com>
35- Reviewed-by: Keith Randall <khr@google.com>
36- Reviewed-by: David Chase <drchase@google.com>
37- LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
38- Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft .com>
39- Upstream-reference: https://github.com/golang/crypto/commit/a1ce0fee129597fdea8dfd58d71b6b607de6bdce.patch
28+
29+ This CVE needs 2 commits for the fix.
30+ Upstream Patch reference:
31+ 1. https://github .com/golang/crypto/commit/e3d1254f1e7e60baa086142c46174bf6d8d0fe50.patch
32+ 2. https://github.com/golang/crypto/commit/a1ce0fee129597fdea8dfd58d71b6b607de6bdce.patch
4033---
41- vendor/golang.org/x/crypto/ssh/agent/client.go | 7 +++++++
42- 1 file changed, 7 insertions(+)
34+ vendor/golang.org/x/crypto/ssh/agent/client.go | 7 +++++++
35+ vendor/golang.org/x/crypto/ssh/agent/keyring.go | 12 +++++++++---
36+ 2 files changed, 16 insertions(+), 3 deletions(-)
4337
4438diff --git a/vendor/golang.org/x/crypto/ssh/agent/client.go b/vendor/golang.org/x/crypto/ssh/agent/client.go
4539index 6dc73e0..d9e7f73 100644
@@ -59,6 +53,35 @@ index 6dc73e0..d9e7f73 100644
5953 cert := key.Certificate
6054 if cert == nil {
6155 return c.insertKey(key.PrivateKey, key.Comment, constraints)
56+ diff --git a/vendor/golang.org/x/crypto/ssh/agent/keyring.go b/vendor/golang.org/x/crypto/ssh/agent/keyring.go
57+ index 21bfa87..64bc105 100644
58+ --- a/vendor/golang.org/x/crypto/ssh/agent/keyring.go
59+ +++ b/vendor/golang.org/x/crypto/ssh/agent/keyring.go
60+ @@ -143,15 +143,21 @@ func (r *keyring) List() ([]*Key, error) {
61+ return ids, nil
62+ }
63+
64+ - // Insert adds a private key to the keyring. If a certificate
65+ - // is given, that certificate is added as public key. Note that
66+ - // any constraints given are ignored.
67+ + // Add adds a private key to the keyring. If a certificate is given, that
68+ + // certificate is added as public key.
69+ + //
70+ + // Add returns an error if key contains ConstraintExtensions.
71+ func (r *keyring) Add(key AddedKey) error {
72+ r.mu.Lock()
73+ defer r.mu.Unlock()
74+ if r.locked {
75+ return errLocked
76+ }
77+ +
78+ + if len(key.ConstraintExtensions) > 0 {
79+ + return errors.New("agent: constraint extensions are present but not supported")
80+ + }
81+ +
82+ signer, err := ssh.NewSignerFromKey(key.PrivateKey)
83+
84+ if err != nil {
6285- -
63- 2.45.4
86+ 2.43.0
6487
0 commit comments