From c3ef550a4befd63a5e835986cdbc8f77a1f93991 Mon Sep 17 00:00:00 2001 From: Acts1631 Date: Fri, 3 Jul 2026 19:38:19 -0400 Subject: [PATCH] main: wipe SSH password/passphrase from environment memory mscp read MSCP_SSH_AUTH_PASSWORD and MSCP_SSH_AUTH_PASSPHRASE via getenv() and kept using the returned pointer for the process lifetime. On Linux, /proc/PID/environ exposes the original exec-time environment block to any local process running as the same uid, so the secret remained readable there for as long as the mscp process ran. Note that unsetenv() alone does not fix this: /proc/PID/environ reflects the raw memory the kernel copied at execve() time, not libc's environ[] bookkeeping that unsetenv()/setenv() manipulate. Verified experimentally: unsetenv() alone leaves the secret fully visible in /proc/PID/environ, while memset()'ing the bytes returned by getenv() actually clears it from that view. Copy the secret to the heap with strdup() and memset() the original environment bytes to zero. This keeps non-interactive usage (scripts, CI pipelines) working exactly as before while removing the secret from /proc/PID/environ for the remainder of the process's life. Verified end-to-end against a local sshd: while a passphrase-gated key-based transfer is in flight, /proc//environ shows MSCP_SSH_AUTH_PASSPHRASE= with an empty value instead of the passphrase. --- src/main.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/main.c b/src/main.c index 0ad58f1..351b435 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -483,8 +484,32 @@ int main(int argc, char **argv) if (quiet) to_dev_null(STDOUT_FILENO); + /* Snapshot password/passphrase from the environment, then wipe + * them in place. getenv() returns a pointer directly into the + * process's original environment block, which stays readable by + * any local process with the same uid via /proc/PID/environ for + * as long as the bytes remain unmodified -- calling unsetenv() + * alone does NOT clear this, since /proc/PID/environ reflects + * the raw exec-time memory, not libc's environ[] bookkeeping. + * Copy the value to the heap, then memset the original bytes to + * remove them from that memory, keeping non-interactive usage + * (scripts, CI) working without leaving the secret exposed for + * the remaining lifetime of the process. + */ s.password = getenv(ENV_SSH_AUTH_PASSWORD); s.passphrase = getenv(ENV_SSH_AUTH_PASSPHRASE); + if (s.password) { + char *p = s.password; + s.password = strdup(p); + memset(p, 0, strlen(p)); + } + if (s.passphrase) { + char *p = s.passphrase; + s.passphrase = strdup(p); + memset(p, 0, strlen(p)); + } + unsetenv(ENV_SSH_AUTH_PASSWORD); + unsetenv(ENV_SSH_AUTH_PASSPHRASE); if ((m = mscp_init(&o, &s)) == NULL) { pr_err("mscp_init: %s", priv_get_err());