Invocation of Process Using Visible Sensitive Information
Description
Invocation of Process Using Visible Sensitive Information is a vulnerability that occurs when a process is invoked with sensitive data passed through command-line arguments, environment variables, or other mechanisms that can be observed by other processes on the operating system. On most operating systems, any user can view the command-line arguments and sometimes environment variables of processes owned by other users through utilities like ps, top, /proc filesystem, or Task Manager. When sensitive information such as passwords, API keys, cryptographic secrets, or personal data is passed through these visible channels, it becomes accessible to local attackers and may be logged in shell histories, process accounting records, or system monitoring tools.
Risk
Passing sensitive information through visible process attributes creates significant security risks in multi-user and shared hosting environments. Local users can extract credentials by simply monitoring process lists, enabling unauthorized access to databases, APIs, and other protected resources. Shell history files may retain commands containing passwords indefinitely, creating persistent exposure even after the immediate process terminates. System monitoring and logging tools often capture command-line arguments, potentially storing credentials in log files accessible to administrators or leaked through log aggregation services. Container orchestration systems and cloud platforms may expose these arguments through their management interfaces. The risk is amplified in development and debugging scenarios where developers may routinely pass credentials on command lines without considering the exposure.
Solution
Never pass sensitive information through command-line arguments or environment variables that may be visible to other processes. Instead, read credentials from configuration files with restricted permissions (mode 600), use credential management systems like HashiCorp Vault or AWS Secrets Manager, or accept input through standard input (stdin). For environment variables, use mechanisms that protect variable visibility or pass references to secrets rather than the secrets themselves. Implement wrapper scripts that read credentials from secure sources and export them only to the child process's private environment. Clear command-line arguments after parsing if the programming language allows. Disable shell history for sessions handling sensitive commands, and configure process accounting to exclude or mask sensitive arguments. Review all process invocations in code for credential exposure.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Sensitive information such as passwords, API keys, and cryptographic secrets becomes readable by other users on the system. This exposure enables unauthorized access to protected resources and may lead to further system compromise. |
Example Code
Vulnerable Code (Python)
The following code demonstrates passing sensitive information through visible channels:
import subprocess
import os
class VulnerableProcessInvoker:
"""Examples of vulnerable process invocation patterns"""
def connect_database_vulnerable(self, password):
# Vulnerable: Password visible in process list via 'ps aux'
# Anyone can run: ps aux | grep mysql
cmd = f"mysql -u admin -p{password} -h localhost mydb"
subprocess.run(cmd, shell=True)
def backup_with_credentials(self, aws_secret):
# Vulnerable: AWS credentials visible in process arguments
cmd = [
"aws", "s3", "sync",
"--access-key-id", "AKIAIOSFODNN7EXAMPLE",
"--secret-access-key", aws_secret,
"/data/", "s3://mybucket/"
]
subprocess.run(cmd)
def curl_with_auth(self, api_key):
# Vulnerable: API key in command line
subprocess.run([
"curl", "-H", f"Authorization: Bearer {api_key}",
"https://api.example.com/data"
])
def run_with_env_visible(self, secret):
# Vulnerable: Environment variable may be visible
# /proc/<pid>/environ on Linux
env = os.environ.copy()
env['SECRET_KEY'] = secret
env['DATABASE_PASSWORD'] = secret
subprocess.run(["./process_data.sh"], env=env)
def pgp_decrypt_vulnerable(self, passphrase):
# Vulnerable: PGP passphrase on command line
# Visible to all users, stored in shell history
cmd = f"gpg --passphrase {passphrase} --decrypt secret.gpg"
subprocess.run(cmd, shell=True)
All examples expose sensitive credentials through command-line arguments visible via ps aux or /proc/<pid>/cmdline.
Fixed Code (Python)
import subprocess
import os
import tempfile
import stat
class SecureProcessInvoker:
"""Secure patterns for process invocation with credentials"""
def connect_database_secure(self, password):
# Fixed: Use MySQL options file with restricted permissions
with tempfile.NamedTemporaryFile(mode='w', suffix='.cnf', delete=False) as f:
f.write(f"[client]\npassword={password}\n")
options_file = f.name
# Set restrictive permissions (owner read only)
os.chmod(options_file, stat.S_IRUSR)
try:
# Password not visible in process list
cmd = ["mysql", f"--defaults-extra-file={options_file}",
"-u", "admin", "-h", "localhost", "mydb"]
subprocess.run(cmd)
finally:
os.unlink(options_file)
def backup_with_credentials_secure(self):
# Fixed: Use AWS credential file or IAM role
# Credentials stored in ~/.aws/credentials with mode 600
# Or use instance profile/IAM role (no credentials needed)
subprocess.run([
"aws", "s3", "sync",
"/data/", "s3://mybucket/"
]) # Uses default credential chain
def curl_with_auth_secure(self, api_key):
# Fixed: Use stdin or config file for sensitive headers
# Option 1: Pass via stdin using -K -
config = f'header = "Authorization: Bearer {api_key}"'
process = subprocess.Popen(
["curl", "-K", "-", "https://api.example.com/data"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE
)
stdout, _ = process.communicate(input=config.encode())
return stdout
def run_with_protected_env(self, secret):
# Fixed: Use a secrets manager or pass via file descriptor
# Create a pipe to pass secret to child process
read_fd, write_fd = os.pipe()
# Write secret to pipe
os.write(write_fd, secret.encode())
os.close(write_fd)
# Child reads from file descriptor
env = os.environ.copy()
env['SECRET_FD'] = str(read_fd) # Just the FD number, not the secret
subprocess.run(["./process_data.sh"], env=env, pass_fds=(read_fd,))
def pgp_decrypt_secure(self, passphrase):
# Fixed: Use pinentry or pass passphrase via file descriptor
process = subprocess.Popen(
["gpg", "--passphrase-fd", "0", "--batch", "--decrypt", "secret.gpg"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
stdout, stderr = process.communicate(input=passphrase.encode())
return stdout
def use_secrets_manager(self):
"""Best practice: Use a secrets manager"""
from secrets_manager import get_secret
# Secret is fetched internally, never on command line
secret = get_secret("database/password")
# Pass to database driver directly, not via subprocess
import mysql.connector
conn = mysql.connector.connect(
host="localhost",
user="admin",
password=secret,
database="mydb"
)
return conn
The fixes use configuration files with restrictive permissions, stdin for passing secrets, file descriptors, credential chains, and secrets managers instead of visible command-line arguments.
Exploited in the Wild
Kubernetes Secrets in Environment Variables (Multiple Cloud Deployments, Ongoing)
Container orchestration platforms have exposed credentials when developers pass secrets as environment variables visible in pod specifications, container inspection commands, and monitoring systems. Attackers with cluster access can enumerate secrets by inspecting running containers. Major cloud providers have documented multiple incidents and now recommend using mounted secrets volumes or external secrets managers instead.
Jenkins Credential Leakage in Build Logs (Multiple Organizations, 2019)
Jenkins build systems frequently logged command-line arguments containing credentials passed to build scripts. These logs were often accessible to developers who shouldn't have access to production credentials, or were exposed through log aggregation systems. This led to Jenkins implementing credential masking and recommending the credentials plugin.
Docker Run Command Credential Exposure (Multiple Organizations, Ongoing)
Docker commands passing credentials via -e PASSWORD=secret expose these values through docker inspect, process lists, and container logs. Security researchers have found exposed database passwords, API keys, and encryption secrets in running containers on compromised hosts. Docker documentation now recommends using Docker secrets for sensitive data.
Tools to Test/Exploit
-
ps aux / top — Standard Unix utilities for viewing process command-line arguments of all running processes.
-
pspy — Tool for monitoring Linux processes without root permissions, useful for capturing credentials in process arguments.
-
Trivy — Container security scanner that detects secrets in environment variables and container configurations.
CVE Examples
-
CVE-2021-32638 — Code analysis product exposed access tokens via command-line parameters and environment variables.
-
CVE-2005-1387 — Application passed passwords on command line viewable via ps command.
-
CVE-2001-1565 — Username and password visible on command line through process listing.
-
CVE-1999-1270 — PGP passphrase provided as command line argument exposed to other users.
-
CVE-2004-1058 — Kernel race condition enabled access to environment variables during process spawning.
References
-
MITRE Corporation. "CWE-214: Invocation of Process Using Visible Sensitive Information." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/214.html
-
Docker Documentation. "Manage Sensitive Data with Docker Secrets." https://docs.docker.com/engine/swarm/secrets/
-
Kubernetes Documentation. "Secrets Security Properties." https://kubernetes.io/docs/concepts/configuration/secret/#security-properties
-
OWASP Foundation. "Credential Management Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Credential_Management_Cheat_Sheet.html