Is your feature request related to a problem? Please describe.
ldcli config --list renders the stored access-token value verbatim, in every output mode:
$ ldcli config --list
{"access-token":"api-<the real token>","environment":"production","project":"my-project"}
Reproduced against 3.9.0 built from main.
Two things make this sharper than it first looks:
- JSON is the default whenever stdout is not a terminal (
cmd/root.go:227-230), so the piped and CI-log path is the one that leaks by default.
config --list is the natural way to confirm that --set landed, so it is a command people are led to run right after storing the token.
The result is the token in terminal scrollback, shell-session captures, screen shares, and CI logs. I hit this in practice: the value ended up in a transcript and the token had to be treated as compromised and rotated.
A second, narrower instance of the same problem is in the --set/--unset validation error, which echoes back the argument it rejected:
$ ldcli config --set api-<the real token> access-token
{"message":"api-<the real token> is not a valid configuration option"}
Transposing the key and value is an easy mistake, and it puts the secret in the error message.
To be explicit about scope: this is not a vulnerability report and I am not filing it as one. No privilege boundary is crossed and no third party gains anything — the CLI is printing the operator's own local secret, on request, to their own terminal. It is a secret-hygiene / defense-in-depth issue. I read SECURITY.md and did not use Bugcrowd for that reason; happy to be redirected if you disagree.
Describe the solution you'd like
Redact the value in output, unconditionally, and leave the stored value untouched:
$ ldcli config --list
{"access-token":"[REDACTED]","environment":"production","project":"my-project"}
config --list answers "is a token configured, and what are my other defaults" — and a redacted marker answers that just as well as the value does. Nothing in the CLI needs the value echoed back to it.
Describe alternatives you've considered
- Redact by default with a
--show-secrets opt-in. Preserves the capability, but it weakens the guarantee to "safe unless someone passes a flag", and a flag that exists to print a secret invites being pasted into scripts and automation. I would rather not add it unless there is a use case that needs it.
- Partial masking (
api-••••••••cd12). Helps a human tell which of several tokens is stored. It still puts characters of a live secret into scrollback, and I do not think the disambiguation is worth that — ldcli whoami already names the token without revealing it.
- Leaving it alone because the config file is readable anyway. Reading
$XDG_CONFIG_HOME/ldcli/config.yml is a deliberate act against a file with a known path. Printing to stdout is passive and ends up in logs and transcripts that outlive the terminal. Those are different exposure profiles.
The config file also means no capability is lost by redacting: anyone who genuinely needs the value can still yq '.["access-token"]' "$XDG_CONFIG_HOME/ldcli/config.yml".
Additional context
I have a PR ready that does both of the above, with tests, and I will link it here.
Is your feature request related to a problem? Please describe.
ldcli config --listrenders the storedaccess-tokenvalue verbatim, in every output mode:Reproduced against 3.9.0 built from
main.Two things make this sharper than it first looks:
cmd/root.go:227-230), so the piped and CI-log path is the one that leaks by default.config --listis the natural way to confirm that--setlanded, so it is a command people are led to run right after storing the token.The result is the token in terminal scrollback, shell-session captures, screen shares, and CI logs. I hit this in practice: the value ended up in a transcript and the token had to be treated as compromised and rotated.
A second, narrower instance of the same problem is in the
--set/--unsetvalidation error, which echoes back the argument it rejected:Transposing the key and value is an easy mistake, and it puts the secret in the error message.
To be explicit about scope: this is not a vulnerability report and I am not filing it as one. No privilege boundary is crossed and no third party gains anything — the CLI is printing the operator's own local secret, on request, to their own terminal. It is a secret-hygiene / defense-in-depth issue. I read SECURITY.md and did not use Bugcrowd for that reason; happy to be redirected if you disagree.
Describe the solution you'd like
Redact the value in output, unconditionally, and leave the stored value untouched:
config --listanswers "is a token configured, and what are my other defaults" — and a redacted marker answers that just as well as the value does. Nothing in the CLI needs the value echoed back to it.Describe alternatives you've considered
--show-secretsopt-in. Preserves the capability, but it weakens the guarantee to "safe unless someone passes a flag", and a flag that exists to print a secret invites being pasted into scripts and automation. I would rather not add it unless there is a use case that needs it.api-••••••••cd12). Helps a human tell which of several tokens is stored. It still puts characters of a live secret into scrollback, and I do not think the disambiguation is worth that —ldcli whoamialready names the token without revealing it.$XDG_CONFIG_HOME/ldcli/config.ymlis a deliberate act against a file with a known path. Printing to stdout is passive and ends up in logs and transcripts that outlive the terminal. Those are different exposure profiles.The config file also means no capability is lost by redacting: anyone who genuinely needs the value can still
yq '.["access-token"]' "$XDG_CONFIG_HOME/ldcli/config.yml".Additional context
I have a PR ready that does both of the above, with tests, and I will link it here.