Description
When running pangolin up in the default detached mode on Linux, the CLI re-spawns itself as an elevated subprocess and passes the OLM device credentials as command-line arguments. The secret is therefore visible to every local process/user via ps / /proc/<pid>/cmdline (which is world-readable on Linux) — twice:
- Transiently, in the argv of the
sudo sh -c "…" wrapper, which contains the fully quoted command string including --secret.
- For the entire lifetime of the daemon, in the argv of the detached
pangolin up client --id … --secret … process.
This happens even when the credentials come from the account store (i.e. the user never typed them): the parent loads them and re-injects them into argv. PANGOLIN_CREDENTIALS_FROM_KEYRING=1 is only a marker telling the subprocess to also fetch the session token — it does not prevent the argv exposure.
Affected code (v0.15.1)
cmd/up/client/client.go:
- Line 327–328: credentials are appended to the subprocess args:
cmdArgs = append(cmdArgs, "--id", olmID)
cmdArgs = append(cmdArgs, "--secret", olmSecret)
- Lines ~400–432: the args are baked into a shell string and run via
sudo sh -c:
shellCmd := "export PANGOLIN_SUBPROCESS=1 && "
...
shellCmd += "nohup"
for _, arg := range shellArgs {
shellCmd += " " + fmt.Sprintf("%q", arg)
}
shellCmd += " >/dev/null 2>&1 &"
...
procCmd = exec.Command("sudo", "sh", "-c", shellCmd)
Reproduction
$ pangolin login # against any Pangolin server
$ pangolin up # default detached mode, authorize sudo
$ ps -eo args | grep "pangolin up client"
/home/user/.local/bin/pangolin up client --org myorg --id abc123… --secret <PLAINTEXT SECRET> --endpoint https://…
The secret stays visible in the process list as long as the client is up. Any unprivileged local user or process can read it:
$ tr '\0' ' ' </proc/$(pgrep -f "pangolin up client")/cmdline
Impact
- The OLM device secret leaks to all local users/processes (world-readable
/proc/*/cmdline).
- It can also end up in process-monitoring/accounting tooling, EDR logs, crash reports, or shared debugging output (
ps snippets pasted into tickets/chats).
- Combined with the endpoint (also in argv), this is enough to register/connect the device identity from elsewhere.
Suggested fix
Avoid argv for the secret entirely; any of these would work:
- Preferred / smallest change: when
PANGOLIN_CREDENTIALS_FROM_KEYRING=1, don't pass --id/--secret at all — the subprocess already reads the account store in that path (it fetches SessionToken from accountStore.ActiveAccount() around line 557–568), so it can read OlmCredentials from the same place.
- Pass the credentials via stdin (e.g. a small JSON blob the subprocess reads when
PANGOLIN_SUBPROCESS=1).
- Pass them via environment variables set through
exec.Cmd.Env (not via export … inside the sh -c string, which is itself argv-visible) — /proc/<pid>/environ is owner-readable only, unlike cmdline.
For the explicit --secret flag use case, keeping the flag but also honoring an env var (e.g. PANGOLIN_OLM_SECRET) would let scripts avoid argv too.
Happy to test a fix — thanks for Pangolin!
Description
When running
pangolin upin the default detached mode on Linux, the CLI re-spawns itself as an elevated subprocess and passes the OLM device credentials as command-line arguments. The secret is therefore visible to every local process/user viaps//proc/<pid>/cmdline(which is world-readable on Linux) — twice:sudo sh -c "…"wrapper, which contains the fully quoted command string including--secret.pangolin up client --id … --secret …process.This happens even when the credentials come from the account store (i.e. the user never typed them): the parent loads them and re-injects them into argv.
PANGOLIN_CREDENTIALS_FROM_KEYRING=1is only a marker telling the subprocess to also fetch the session token — it does not prevent the argv exposure.Affected code (v0.15.1)
cmd/up/client/client.go:sudo sh -c:Reproduction
The secret stays visible in the process list as long as the client is up. Any unprivileged local user or process can read it:
Impact
/proc/*/cmdline).pssnippets pasted into tickets/chats).Suggested fix
Avoid argv for the secret entirely; any of these would work:
PANGOLIN_CREDENTIALS_FROM_KEYRING=1, don't pass--id/--secretat all — the subprocess already reads the account store in that path (it fetchesSessionTokenfromaccountStore.ActiveAccount()around line 557–568), so it can readOlmCredentialsfrom the same place.PANGOLIN_SUBPROCESS=1).exec.Cmd.Env(not viaexport …inside thesh -cstring, which is itself argv-visible) —/proc/<pid>/environis owner-readable only, unlike cmdline.For the explicit
--secretflag use case, keeping the flag but also honoring an env var (e.g.PANGOLIN_OLM_SECRET) would let scripts avoid argv too.Happy to test a fix — thanks for Pangolin!