Steps to Reproduce
Run any command that shells out to step-kms-plugin with a credential supplied inline in the KMS
URI, and have the plugin call fail. For example:
step certificate create --profile root-ca \
--kms "yubikey:serial=<SERIAL>;pin-value=<YOUR-PIN>" \
--key "yubikey:slot-id=9c" --not-after 87600h "My Root CA" root_ca.crt
When the plugin subprocess exits non-zero for any reason (wrong PIN, a touch-policy timeout, etc.),
step prints the full command line it ran — including the pin-value= you supplied.
This is not specific to YubiKey or to certificate create: it affects any KMS URI that carries an
inline credential, on any step command that runs the plugin, because the error wrapper embeds the
entire plugin argv. It is also visible by inspection in
internal/cryptoutil/cryptoutil.go — exitError formats cmd.String() into the returned error.
Your Environment
- OS - Windows 11 (the affected code path is OS-agnostic; macOS/Linux are equally affected)
step CLI Version - 0.30.6 (with step-kms-plugin 0.17.0)
Expected Behavior
Secrets supplied through the documented pin-value= (and management-key=, client-secret=)
mechanism should not appear in cleartext in error output. The echoed command is genuinely useful for
debugging, so the fix is to redact the credential values, not to drop the echo.
Actual Behavior
The credential is printed verbatim on stderr. For example:
error creating certificate request: command "…\step-kms-plugin.exe sign --format base64 --kms yubikey:serial=<SERIAL>;pin-value=<YOUR-PIN-IN-CLEARTEXT> yubikey:slot-id=9c" failed with:
Error: command failed: smart card error 6982: security status not satisfied
pin-value= is the documented way to supply the PIN non-interactively, so using the feature as
designed puts the secret on stderr on any failure — where it lands in console scrollback, session
transcripts, and CI logs, and (because this error text is exactly what people paste into bug
reports) potentially public issue trackers.
Additional Context
- Root cause:
exitError in internal/cryptoutil/cryptoutil.go formats cmd.String() (the full
plugin argv — the --kms URI plus the positional key URI) into
fmt.Errorf("command %q failed with: …"), and passes the plugin's stderr through verbatim.
- Affected attributes across the KMS URI schemes the crypto library parses:
pin-value
(yubikey/pkcs11/capi), management-key (yubikey), client-secret (azurekms). pin-source,
management-key-source, and credentials-file are file paths (not secrets).
- The
6982 in the example is an unrelated touch-policy timeout; the leak occurs on any plugin
failure, not just that one.
Contributing
Vote on this issue by adding a 👍 reaction.
To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).
Steps to Reproduce
Run any command that shells out to
step-kms-pluginwith a credential supplied inline in the KMSURI, and have the plugin call fail. For example:
When the plugin subprocess exits non-zero for any reason (wrong PIN, a touch-policy timeout, etc.),
stepprints the full command line it ran — including thepin-value=you supplied.This is not specific to YubiKey or to
certificate create: it affects any KMS URI that carries aninline credential, on any
stepcommand that runs the plugin, because the error wrapper embeds theentire plugin argv. It is also visible by inspection in
internal/cryptoutil/cryptoutil.go—exitErrorformatscmd.String()into the returned error.Your Environment
stepCLI Version - 0.30.6 (with step-kms-plugin 0.17.0)Expected Behavior
Secrets supplied through the documented
pin-value=(andmanagement-key=,client-secret=)mechanism should not appear in cleartext in error output. The echoed command is genuinely useful for
debugging, so the fix is to redact the credential values, not to drop the echo.
Actual Behavior
The credential is printed verbatim on stderr. For example:
pin-value=is the documented way to supply the PIN non-interactively, so using the feature asdesigned puts the secret on stderr on any failure — where it lands in console scrollback, session
transcripts, and CI logs, and (because this error text is exactly what people paste into bug
reports) potentially public issue trackers.
Additional Context
exitErrorininternal/cryptoutil/cryptoutil.goformatscmd.String()(the fullplugin argv — the
--kmsURI plus the positional key URI) intofmt.Errorf("command %q failed with: …"), and passes the plugin's stderr through verbatim.pin-value(yubikey/pkcs11/capi),
management-key(yubikey),client-secret(azurekms).pin-source,management-key-source, andcredentials-fileare file paths (not secrets).6982in the example is an unrelated touch-policy timeout; the leak occurs on any pluginfailure, not just that one.
Contributing
Vote on this issue by adding a 👍 reaction.
To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).