From 90eecef6d712542cd3f7ce5f662db8f177393021 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 6 Feb 2026 17:56:16 +0100 Subject: [PATCH] cli/command/registry: preserve all whitespace in secrets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preserve all whitespace and treat the secret as an opaque value, leaving it to the registry to (in)validate. We still check for empty values in some places. This partially reverts a21a5f42433267052441cdb7ebe7604dfcc7f159, but checks for empty (whitespace-only) passwords without mutating the value. This better aligns with [NIST SP 800-63B §5.1.1.2], which describes that the value should be treated as opaque, preserving any other whitespace, including newlines. Note that trimming whitespace may still happen elsewhere (see [NIST SP 800-63B (revision 4) §3.1.1.2]); > Verifiers **MAY** make limited allowances for mistyping (e.g., removing > leading and trailing whitespace characters before verification, allowing > the verification of passwords with differing cases for the leading character) [NIST SP 800-63B §5.1.1.2]: https://pages.nist.gov/800-63-3/sp800-63b.html#memsecretver [NIST SP 800-63B (revision 4) §3.1.1.2]: https://pages.nist.gov/800-63-4/sp800-63b.html#passwordver Signed-off-by: Sebastiaan van Stijn --- cli/command/registry.go | 4 +-- cli/command/registry/login_test.go | 50 ++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/cli/command/registry.go b/cli/command/registry.go index 452e2d7354cc..75b979e18561 100644 --- a/cli/command/registry.go +++ b/cli/command/registry.go @@ -144,8 +144,8 @@ func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword } } - argPassword = strings.TrimSpace(argPassword) - if argPassword == "" { + isEmpty := strings.TrimSpace(argPassword) == "" + if isEmpty { restoreInput, err := prompt.DisableInputEcho(cli.In()) if err != nil { return registrytypes.AuthConfig{}, err diff --git a/cli/command/registry/login_test.go b/cli/command/registry/login_test.go index 9537f008b486..b392dab444a9 100644 --- a/cli/command/registry/login_test.go +++ b/cli/command/registry/login_test.go @@ -339,6 +339,56 @@ func TestRunLogin(t *testing.T) { }, }, }, + { + doc: "password with leading and trailing spaces", + priorCredentials: map[string]configtypes.AuthConfig{}, + input: loginOptions{ + serverAddress: "reg1", + user: "my-username", + password: " my password with spaces ", + }, + expectedCredentials: map[string]configtypes.AuthConfig{ + "reg1": { + Username: "my-username", + Password: " my password with spaces ", + ServerAddress: "reg1", + }, + }, + }, + { + doc: "password stdin with line-endings", + priorCredentials: map[string]configtypes.AuthConfig{}, + stdIn: " my password with spaces \r\n", + input: loginOptions{ + serverAddress: "reg1", + user: "my-username", + passwordStdin: true, + }, + expectedCredentials: map[string]configtypes.AuthConfig{ + "reg1": { + Username: "my-username", + Password: " my password with spaces ", + ServerAddress: "reg1", + }, + }, + }, + { + doc: "password stdin with multiple line-endings", + priorCredentials: map[string]configtypes.AuthConfig{}, + stdIn: " my password\nwith spaces \r\n\r\n", + input: loginOptions{ + serverAddress: "reg1", + user: "my-username", + passwordStdin: true, + }, + expectedCredentials: map[string]configtypes.AuthConfig{ + "reg1": { + Username: "my-username", + Password: " my password\nwith spaces \r\n", + ServerAddress: "reg1", + }, + }, + }, } for _, tc := range testCases {