CVE-2023-24827: Insertion of Sensitive Information into Log File (CWE-532)
value: syft is a a CLI tool and Go library for generating a Software Bill of Materials (SBOM) from container images and filesystems. A password disclosure flaw was found in Syft versions v0.69.0 and v0.69.1. This flaw leaks the password stored in the SYFT_ATTEST_PASSWORD environment variable. The `SYFT_ATTEST_PASSWORD` environment variable is for the `syft attest` command to generate attested SBOMs for the given container image. This environment variable is used to decrypt the private key (provided with `syft attest --key <path-to-key-file>`)  during the signing process while generating an SBOM attestation. This vulnerability affects users running syft that have the `SYFT_ATTEST_PASSWORD` environment variable set with credentials (regardless of if the attest command is being used or not). Users that do not have the environment variable `SYFT_ATTEST_PASSWORD` set are not affected by this issue. The credentials are leaked in two ways: in the syft logs when `-vv` or `-vvv` are used in the syft command (which is any log level >= `DEBUG`) and in the attestation or SBOM only when the `syft-json` format is used. Note that as of v0.69.0 any generated attestations by the `syft attest` command are uploaded to the OCI registry (if you have write access to that registry) in the same way `cosign attach` is done. This means that any attestations generated for the affected versions of syft when the `SYFT_ATTEST_PASSWORD` environment variable was set would leak credentials in the attestation payload uploaded to the OCI registry. This issue has been patched in commit `9995950c70` and has been released as v0.70.0. There are no workarounds for this vulnerability. Users are advised to upgrade.
CWE description: Information written to log files can be of a sensitive nature and give valuable guidance to an attacker or expose sensitive user information.
CVSS v3 base score: 7.5
Published: 2023-02-07T01:15Z
Repository: https://github.com/anchore/syft
Language: Go
Files changed: internal/config/attest.go, test/cli/packages_cmd_test.go
Commit date: 2023-02-03 18:06:14 +0000
Commit message: fix: update config struct to not decode password/key (#1538)

* fix: update config struct to not decode password/key
* test: update tests to confirm no secrets in output

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
---------

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
Diff: diff --git a/internal/config/attest.go b/internal/config/attest.go
index f0493d7b..659c7d3e 100644
--- a/internal/config/attest.go
+++ b/internal/config/attest.go
@@ -1,12 +1,13 @@
 package config
 
 import "github.com/spf13/viper"
 
 type attest struct {
-	Key      string `yaml:"key" json:"key" mapstructure:"key"`
-	Password string `yaml:"password" json:"password" mapstructure:"password"`
+	// IMPORTANT: do not show the attestation key/password in any YAML/JSON output (sensitive information)
+	Key      string `yaml:"-" json:"-" mapstructure:"key"`
+	Password string `yaml:"-" json:"-" mapstructure:"password"`
 }
 
 func (cfg attest) loadDefaultValues(v *viper.Viper) {
 	v.SetDefault("attest.key", "")
 	v.SetDefault("attest.password", "")
diff --git a/test/cli/packages_cmd_test.go b/test/cli/packages_cmd_test.go
index 6a768dcd..20ec9fa7 100644
--- a/test/cli/packages_cmd_test.go
+++ b/test/cli/packages_cmd_test.go
@@ -227,10 +227,24 @@ func TestPackagesCmdFlags(t *testing.T) {
 				assertInOutput("parallelism=1"),
 				assertPackageCount(34),
 				assertSuccessfulReturnCode,
 			},
 		},
+		{
+			name: "password and key not in config output",
+			args: []string{"packages", "-vvv", "-o", "json", coverageImage},
+			env: map[string]string{
+				"SYFT_ATTEST_PASSWORD": "secret_password",
+				"SYFT_ATTEST_KEY":      "secret_key_path",
+			},
+			assertions: []traitAssertion{
+				assertNotInOutput("secret_password"),
+				assertNotInOutput("secret_key_path"),
+				assertPackageCount(34),
+				assertSuccessfulReturnCode,
+			},
+		},
 	}
 
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
 			cmd, stdout, stderr := runSyft(t, test.env, test.args...)

Vulnerable code: 	Key      string `yaml:"key" json:"key" mapstructure:"key"`
	Password string `yaml:"password" json:"password" mapstructure:"password"`
Fixed code: 	// IMPORTANT: do not show the attestation key/password in any YAML/JSON output (sensitive information)
	Key      string `yaml:"-" json:"-" mapstructure:"key"`
	Password string `yaml:"-" json:"-" mapstructure:"password"`
		{
			name: "password and key not in config output",
			args: []string{"packages", "-vvv", "-o", "json", coverageImage},
			env: map[string]string{
				"SYFT_ATTEST_PASSWORD": "secret_password",
				"SYFT_ATTEST_KEY":      "secret_key_path",
			},
			assertions: []traitAssertion{
				assertNotInOutput("secret_password"),
				assertNotInOutput("secret_key_path"),
				assertPackageCount(34),
				assertSuccessfulReturnCode,
			},
		},