From 7bb3e1de5301c5c242930ee89dd17ccce7ab3037 Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Mon, 20 Apr 2026 16:25:29 -0700 Subject: [PATCH 1/2] Reject STELLAR_SECRET_KEY when --secure-store is requested. --- cmd/crates/soroban-test/tests/it/config.rs | 25 ++++++++++++++++++++++ cmd/soroban-cli/src/commands/keys/add.rs | 18 +++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/cmd/crates/soroban-test/tests/it/config.rs b/cmd/crates/soroban-test/tests/it/config.rs index 633416734..d69d7956c 100644 --- a/cmd/crates/soroban-test/tests/it/config.rs +++ b/cmd/crates/soroban-test/tests/it/config.rs @@ -195,6 +195,31 @@ fn seed_phrase() { .stdout(predicates::str::contains("test_seed\n")); } +#[test] +fn secure_store_rejects_env_secret_key() { + let sandbox = TestEnv::default(); + + // --secure-store with STELLAR_SECRET_KEY set should be rejected rather than + // silently writing the raw secret to a plaintext identity file. + sandbox + .new_assert_cmd("keys") + .env( + "STELLAR_SECRET_KEY", + "SDIY6AQQ75WMD4W46EYB7O6UYMHOCGQHLAQGQTKHDX4J2DYQCHVCQYFD", + ) + .arg("add") + .arg("alice") + .arg("--secure-store") + .assert() + .failure(); + + // The identity file must not exist — no plaintext fallback. + assert!( + !sandbox.config_dir().join("identity/alice.toml").exists(), + "identity file should not be created when --secure-store is rejected" + ); +} + #[test] fn use_env() { let sandbox = TestEnv::default(); diff --git a/cmd/soroban-cli/src/commands/keys/add.rs b/cmd/soroban-cli/src/commands/keys/add.rs index 999884eec..64aa4271b 100644 --- a/cmd/soroban-cli/src/commands/keys/add.rs +++ b/cmd/soroban-cli/src/commands/keys/add.rs @@ -33,6 +33,12 @@ pub enum Error { #[error("An identity with the name '{0}' already exists")] IdentityAlreadyExists(String), + + #[error( + "--secure-store only supports seed phrases; \ + unset STELLAR_SECRET_KEY or provide a seed phrase instead" + )] + SecureStoreRequiresSeedPhrase, } #[derive(Debug, clap::Parser, Clone)] @@ -82,9 +88,15 @@ impl Cmd { } fn read_secret(&self, print: &Print) -> Result { - if let Ok(secret_key) = std::env::var("STELLAR_SECRET_KEY") { - Ok(Secret::SecretKey { secret_key }) - } else if self.secrets.secure_store { + if self.secrets.secure_store { + if std::env::var("STELLAR_SECRET_KEY").is_ok() { + return Err(Error::SecureStoreRequiresSeedPhrase); + } + } else if let Ok(secret_key) = std::env::var("STELLAR_SECRET_KEY") { + return Ok(Secret::SecretKey { secret_key }); + } + + if self.secrets.secure_store { let prompt = "Type a 12/24 word seed phrase:"; let secret_key = read_password(print, prompt)?; if secret_key.split_whitespace().count() < 24 { From 20bd2d90099ec1e9b7a2a5856682bd98c60f9273 Mon Sep 17 00:00:00 2001 From: Nando Vieira Date: Mon, 20 Apr 2026 16:53:13 -0700 Subject: [PATCH 2/2] Apply pr feedback. --- cmd/crates/soroban-test/tests/it/config.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/crates/soroban-test/tests/it/config.rs b/cmd/crates/soroban-test/tests/it/config.rs index d69d7956c..33b531b1e 100644 --- a/cmd/crates/soroban-test/tests/it/config.rs +++ b/cmd/crates/soroban-test/tests/it/config.rs @@ -211,7 +211,10 @@ fn secure_store_rejects_env_secret_key() { .arg("alice") .arg("--secure-store") .assert() - .failure(); + .failure() + .stderr(predicate::str::contains( + "--secure-store only supports seed phrases", + )); // The identity file must not exist — no plaintext fallback. assert!(