Skip to content

Secret redaction in logs

Butler Sheet Icons automatically removes passwords, API keys, tokens, and other sensitive values from log output. This is on by default, requires no setup, and applies to every log message written during a run — including log messages emitted by third-party libraries, stack traces from unhandled errors, and crash dump files.

This page explains what is redacted, where the redaction happens, and what to do if you ever need to look at a redacted value while troubleshooting.

What is redacted?

Two kinds of redaction run together. Both are best-effort and run automatically.

Property names that are always redacted

When Butler Sheet Icons logs an options object — for example, the full command-line options passed to qseow create-sheet-thumbnails — any property whose name is in the secret allow-list is replaced with ***redacted*** before the object is written to the log.

The allow-list covers the property names most likely to contain a credential, including (case-insensitive):

  • logonpwd
  • apikey, apiKey, api_key
  • apiToken, api_token
  • password, pwd, passwd
  • passphrase
  • secret, token
  • authorization
  • accessKey, access_key
  • clientSecret, client_secret
  • BSI_CLOUD_API_KEY, BSI_QSEOW_CST_LOGON_PWD, BSI_QSEOW_CST_CERT_FILE, BSI_QSEOW_CST_CERTKEY_FILE

If you add a new option that carries a credential, add the property name to the allow-list in the source code so it is redacted on the next run.

Patterns that are always redacted in text

The redaction also matches common patterns in free text, so log messages and stack traces that mention secrets in passing are cleaned up as well. The text [REDACTED] is substituted for the matched value. The following patterns are recognised:

  • URLs with embedded credentialshttps://user:secret@host/... becomes https://[REDACTED]@host/...
  • Authorization headersAuthorization: Bearer eyJhbGciOi… becomes Authorization: Bearer [REDACTED]. The same applies to Basic … and Token … schemes.
  • key=value and key:value patternspassword=hunter2, api_key=abcdef, clientSecret: topsecret, and similar. The recognised key names are close to the property-name allow-list above, but not identical: this pattern also matches a bare auth, and it does not match the BSI_* environment variable names. Note that a match written with a colon is rewritten using =, so clientSecret: topsecret appears in the log as clientSecret=[REDACTED].
  • JSON-style quoted secrets"password": "mysecret" becomes "password": "[REDACTED]".

Where does the redaction happen?

The redaction is implemented in two places:

  1. In the logging pipeline. Every log line that goes through the Winston logger is run through a redaction step before it is written to the console. This means secrets are redacted even if a third-party library tries to log them.
  2. In crash dump files. Crash dump files apply the same best-effort text-pattern redaction to captured error messages and stack traces before they are written to disk.

In both places, the redaction runs on the message text after your code has produced it. It cannot look inside encrypted blobs or pull secrets out of binary attachments.

What does redacted output look like?

Before

BSI.CORE 2026-06-24 10:30:45 debug: Options: {
  "host": "qlik.example.com",
  "engineport": 4747,
  "apikey": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.abc.def",
  "logonpwd": "hunter2",
  "tenanturl": "https://tenant.eu.qlikcloud.com"
}

After

BSI.CORE 2026-06-24 10:30:45 debug: Options: {
  "host": "qlik.example.com",
  "engineport": 4747,
  "apikey": "***redacted***",
  "logonpwd": "***redacted***",
  "tenanturl": "https://tenant.eu.qlikcloud.com"
}

The non-secret properties are preserved as-is so the logs remain useful for troubleshooting. The tenanturl is left intact because it is a host name, not a credential.

What if I need to see a redacted value?

There is no off switch for redaction. This is by design: silently disabling redaction in production is exactly the kind of mistake that leaks credentials into shared log files.

If you are troubleshooting a problem and the redacted value is what you need, the right approach is to look at the value in its original source — for example, the environment variable, the command-line flag, or the certificate file. Run Butler Sheet Icons with --loglevel debug to see the full log message; the surrounding non-secret fields will still be visible, which is usually enough to confirm the option was passed in correctly.

If you find yourself wanting to log a specific property that should be visible in debug output, that is a sign the property should not be on the secret allow-list. In that case, raise an issue describing the use case rather than disabling redaction.

What if the redaction is too aggressive?

If the redaction is matching text that is not actually a secret (for example, a long random-looking string that happens to look like a bearer token), please open an issue with the log line and a description of the false positive. The patterns are tuned to be conservative, but a balance has to be struck between false positives and false negatives.

What is the difference between secret redaction in logs and in crash dumps?

Log redaction and crash dump redaction overlap, but they are not identical. Crash dumps reuse the same best-effort text-pattern redaction for error messages and stack traces, while normal log redaction also applies the object-property allow-list when Butler Sheet Icons logs structured option/config objects. A crash dump file should still be treated with care: the redaction makes accidental disclosure much less likely, but it is not a guarantee. Always read the file before sharing it.

  • Crash dump files — what is in a crash dump, where the files are written, and how to share them with support.
  • Environment variables — how to set BSI_LOG_LEVEL and other environment variables on Windows, macOS, and Linux.
  • Security — signing, disclosure, and other security topics.

Released under the MIT License.