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

ImpactDetails
ConfidentialityScope: 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

  1. MITRE Corporation. "CWE-214: Invocation of Process Using Visible Sensitive Information." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/214.html

  2. Docker Documentation. "Manage Sensitive Data with Docker Secrets." https://docs.docker.com/engine/swarm/secrets/

  3. Kubernetes Documentation. "Secrets Security Properties." https://kubernetes.io/docs/concepts/configuration/secret/#security-properties

  4. OWASP Foundation. "Credential Management Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Credential_Management_Cheat_Sheet.html