Skip to content

[Bug]: step prints KMS URI secrets (pin-value, etc.) in cleartext when step-kms-plugin fails #1668

Description

@TicketWindowSeat

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.goexitError 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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugneeds triageWaiting for discussion / prioritization by team

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions