Skip to content

Instantly share code, notes, and snippets.

@schlessera
Last active August 6, 2024 11:31
Show Gist options
  • Save schlessera/9851022e03cd669540cb3dfc3cb37915 to your computer and use it in GitHub Desktop.
Save schlessera/9851022e03cd669540cb3dfc3cb37915 to your computer and use it in GitHub Desktop.
#!/bin/env bash
# Mask sensitive key-value pairs in the output of the `env` command.
# This script is intended to be used as a filter for the `env` command output.
# It will replace the value of any key in the SENSITIVE_KEYS list with asterisks.
# Author: Alain Schlesser
# Link to the source gist: https://gist.github.com/schlessera/9851022e03cd669540cb3dfc3cb37915
# Original mention: https://x.com/schlessera/status/1820074260934566102
# Instructions for use:
# 1. Save this script to a file named `mask-sensitive-key-value-pairs`.
# 2. Make the script executable with `chmod +x mask-sensitive-key-value-pairs`.
# 3. Add the directory where the script is saved to your PATH. (or move the script to a directory already in your PATH)
# 4. Run `env | mask-sensitive-key-value-pairs` to mask sensitive key-value pairs in the output of the `env` command.
# 5. Optionally, you can create an alias for the `env` command to always use this script as a filter:
# `alias env='env | mask-sensitive-key-value-pairs'`
# Add this alias to your shell configuration file to make it permanent.
# Provide a list of name components that might denote a senstiive key-value pair.
# This list is used to match the key in the key-value pair.
# Add any additional keys to this list to mask them in the output.
declare -a SENSITIVE_KEYS
SENSITIVE_KEYS+=("KEY") # i.e. "OPENAI_API_KEY"
SENSITIVE_KEYS+=("TOKEN") # i.e. "GITHUB_TOKEN"
# Assemble the list of sensitive keys into a regex pattern.
SENSITIVE_KEYS_PATTERN=$(IFS='|'; echo "${SENSITIVE_KEYS[*]}")
# Assemble the awk script to mask sensitive key-value pairs.
# The script will replace the value of any key in the SENSITIVE_KEYS list with asterisks.
# The script will print the key-value pairs with the value replaced by asterisks.
AWK_SCRIPT="
BEGIN { OFS = \"=\" } # Set the output field separator to '=', important for the final print statement.
\$1 ~ /($SENSITIVE_KEYS_PATTERN)/ { # If the first field matches 'KEY' or 'TOKEN'...
len = length(\$2) # Get the length of the second field, which is the value to replace.
\$2 = sprintf(\"%*s\", len, \" \") # Replace the second field with a string of spaces of the same length.
gsub(/ /, \"*\", \$2) # Replace all spaces in the second field with asterisks.
}
{ print \$1, \$2 } # Print the first and second fields. They will be separated by the output field separator '='.
"
# Run the awk script with '=' as the field separator for parsing the input.
# The input would typically be the output of the `env` command, but it can be applied to other similar key-value pair outputs.
awk -F '=' "$AWK_SCRIPT"
@schlessera
Copy link
Author

@matthieutirelli-pro
Copy link

I went even a bit stronger, I put cat and env to use mask-sensitive-key-values-pair.

alias env='env | mask-sensitive-keys'
function cat() {=
  command cat "$@" | mask-sensitive-keys=
}
#!/bin/zsh

# Mask sensitive key-value pairs in the output of the `env` command.
# This script is intended to be used as a filter for the `env` command output.
# It will replace the value of any key in the SENSITIVE_KEYS list with asterisks.
# Author: Alain Schlesser
# Link to the source gist: https://gist.github.com/schlessera/9851022e03cd669540cb3dfc3cb37915
# Original mention: https://x.com/schlessera/status/1820074260934566102

# Instructions for use:
# 1. Save this script to a file named `mask-sensitive-key-value-pairs`.
# 2. Make the script executable with `chmod +x mask-sensitive-key-value-pairs`.
# 3. Add the directory where the script is saved to your PATH. (or move the script to a directory already in your PATH)
# 4. Run `env | mask-sensitive-key-value-pairs` to mask sensitive key-value pairs in the output of the `env` command.
# 5. Optionally, you can create an alias for the `env` command to always use this script as a filter:
#    `alias env='env | mask-sensitive-key-value-pairs'`
#    Add this alias to your shell configuration file to make it permanent.

# Provide a list of name components that might denote a senstiive key-value pair.
# This list is used to match the key in the key-value pair.
# Add any additional keys to this list to mask them in the output.

declare -a SENSITIVE_KEYS
SENSITIVE_KEYS+=("KEY")      # i.e. "OPENAI_API_KEY"
SENSITIVE_KEYS+=("TOKEN")    # i.e. "GITHUB_TOKEN"

# Assemble the list of sensitive keys into a regex pattern.
SENSITIVE_KEYS_PATTERN=$(IFS='|'; echo "${SENSITIVE_KEYS[*]}")

# Assemble the awk script to mask sensitive key-value pairs.
# The script will replace the value of any key in the SENSITIVE_KEYS list with asterisks.
# The script will print the key-value pairs with the value replaced by asterisks.
AWK_SCRIPT="
    BEGIN { OFS = \"=\" }                   # Set the output field separator to '=', important for the final print statement.
    \$1 ~ /($SENSITIVE_KEYS_PATTERN)/ {     # If the first field matches 'KEY' or 'TOKEN'...
        len = length(\$2)                   #     Get the length of the second field, which is the value to replace.
        \$2 = sprintf(\"%*s\", len, \" \")  #     Replace the second field with a string of spaces of the same length.
        gsub(/ /, \"*\", \$2)               #     Replace all spaces in the second field with asterisks.
    }
    { print \$1, \$2 }                      # Print the first and second fields. They will be separated by the output field separator '='.
"

# Run the awk script with '=' as the field separator for parsing the input.
# The input would typically be the output of the env command, but it can be applied to other similar key-value pair outputs.
if [[ "$DUMP_SECRETS" == "1" ]]; then
        cat
else
        awk -F '=' "$AWK_SCRIPT"
fi

I just need to figure out a way to handle multiple lines secrets :

➜  ~ cat .example 
TEST=DEMO
KEY=*******
APNS_KEY=****************************
THIS IS SUPPOSED TO BE SECRET=
BECAUSE WE WANT TO HANDLE MULTIPLE LINES=
-----END PRIVATE KEY-----"=*
➜  ~ DUMP_SECRETS=1 cat .example
TEST=DEMO
KEY=1234567
APNS_KEY="-----BEGIN PRIVATE KEY-----
THIS IS SUPPOSED TO BE SECRET
BECAUSE WE WANT TO HANDLE MULTIPLE LINES
-----END PRIVATE KEY-----"

@schlessera
Copy link
Author

Nice one, @matthieutirelli-pro ! I had already thought about masking cat and bat too, but thought that might be more error-prone and have more side-effects. Keep me updated! :)

@schlessera
Copy link
Author

@matthieutirelli-pro I was wondering about the typos in your intial alias post, with the trailing = signs.

An empty line (or similar whitespaces not sticking to the initial awk script's assumption of key-value pairs) will end up being transformed into an = sign.

The script will need to be made smarter to deal with non-env output.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment