The AcceptEnv
directive in /etc/ssh/sshd_config
controls which client environment variables get propagated to the server session. While convenient for configuration management, its unrestricted use (AcceptEnv *
) introduces significant security vulnerabilities.
Three primary attack vectors emerge from unrestricted environment variable acceptance:
# Example of dangerous variables that could be injected:
AcceptEnv LD_PRELOAD PATH IFS LANG TZ SSH_*
- LD_PRELOAD Hijacking: Attackers can load malicious libraries by setting
LD_PRELOAD
before executing privileged operations - PATH Manipulation: Modified PATH variables can redirect command execution to attacker-controlled binaries
- Shell Injection: Variables like IFS (Internal Field Separator) can alter shell parsing behavior
Consider this attack chain when AcceptEnv *
is enabled:
# Attacker's client-side command:
ssh -o SendEnv=LD_PRELOAD server.example.com
# Malicious environment being set:
export LD_PRELOAD=/tmp/evil.so
The attacker's shared object gets loaded into every process spawned by SSH, potentially compromising the entire session.
Instead of wildcard acceptance, explicitly enumerate required variables:
# /etc/ssh/sshd_config
AcceptEnv LANG LC_* MY_APP_CONFIG SSH_CONNECTION
For dynamic environment needs, consider these alternatives:
Option 1: ForcedCommand with Environment Filtering
Match User deploy-user
ForceCommand /usr/local/bin/env-filter.sh
Where env-filter.sh
contains:
#!/bin/bash
# Only allow safe variables
export ALLOWED_VARS="VAR1 VAR2 VAR3"
for var in $ALLOWED_VARS; do
[ -n "${!var}" ] && export $var="${!var}"
done
exec "${SSH_ORIGINAL_COMMAND:-$SHELL}"
Option 2: SSH AuthorizedKeysCommand with Variable Validation
# ~/.ssh/authorized_keys
command="/usr/local/bin/validate-env" ssh-rsa AAAAB3...
The validation script:
#!/usr/bin/env python3
import os
import sys
ALLOWED_ENV = {'DEPLOY_ENV', 'BUILD_ID'}
def main():
clean_env = {k:v for k,v in os.environ.items()
if k in ALLOWED_ENV}
# Spawn shell with cleaned environment
os.execve('/bin/bash', ['bash', '-i'], clean_env)
if __name__ == '__main__':
main()
To identify currently accepted variables across your infrastructure:
# Find all sshd_config files accepting environment variables
find /etc/ssh/ -name sshd_config -exec grep -l 'AcceptEnv' {} \;
# Check which variables are actually being sent
ssh -vvv user@host 2>&1 | grep -i "sending env"
Remember that any variable accepted becomes part of the server's attack surface. Periodically review your accepted variables just as you would review user permissions.
When configuring OpenSSH servers, the AcceptEnv
directive in sshd_config
controls which client environment variables get transferred to the server session. While convenient, using AcceptEnv *
creates significant security vulnerabilities:
# DANGEROUS configuration in /etc/ssh/sshd_config:
AcceptEnv *
Attackers can manipulate environment variables to:
- Inject malicious library paths via
LD_PRELOAD
/LD_LIBRARY_PATH
- Override critical paths using
PATH
manipulation - Bypass security controls through
TERM
orSHELL
hijacking - Leak sensitive information via
SSH_*
variables
Consider this attack sequence when AcceptEnv *
is enabled:
# Attacker's malicious environment
export LD_PRELOAD=/tmp/evil.so
export PATH=/malicious/bin:$PATH
# SSH connection with poisoned environment
ssh -o SendEnv=* vulnerable-server.example.com
The server would then load the attacker's shared library and use their compromised PATH.
Instead of using *
, explicitly list required variables:
# Secure configuration in /etc/ssh/sshd_config:
AcceptEnv LANG LC_* MY_APP_CONFIG PROJECT_ID DEPLOY_ENV
For dynamic variables, consider these approaches:
# Client-side script to extract needed variables
env | grep -E '^APP_|^DEPLOY_' | awk '{print "SendEnv", $1}' > ssh_config_snippet
# Server-side filtering script in ~/.ssh/rc
for var in ${!APP_*}; do
# Validate and sanitize each variable
[[ ${!var} =~ ^[a-zA-Z0-9_=/.-]+$ ]] || unset "$var"
done
- Maintain an allowlist of approved variables
- Validate variable contents server-side
- Consider using SSH ForceCommand wrappers for validation
- Log and monitor unusual environment variable patterns
Remember that environment variables form part of the attack surface. Treat them with the same security consideration as other input vectors.