Skip to content

[Bug]: cmd.run OSError messages leak env vars and stdin into logs and API return events #69075

@co-cy

Description

@co-cy

What happened?

Description

When a cmd.run (or any of cmd.*) invocation fails to start the underlying subprocess — typically a routine ENOENT because the binary path has a typo, but any spawn-time errno triggers it — the handler in salt/modules/cmdmod.py builds a CommandExecutionError whose message dumps the entire subprocess kwargs dict:

try:
    proc = salt.utils.timed_subprocess.TimedProc(cmd, **new_kwargs)
except OSError as exc:
    msg = "Unable to run command '{}' with the context '{}', reason: {}".format(
        cmd if output_loglevel is not None else "REDACTED",
        new_kwargs,        # <-- contains env and stdin
        exc,
    )
    raise CommandExecutionError(msg)

new_kwargs includes two fields that routinely carry secrets:

  • env — the run environment. Callers pass credentials via cmd.run "..." env='{"DB_PASSWORD": "..."}', or states pull a credential out of pillar and set it as an env var for a child binary. This is documented usage.
  • stdin — the bytes piped to the command. The standard pattern for feeding a password to a CLI without putting it on the argv (where it would show up in ps) is to write it on stdin. mysql -p, gpg --batch --passphrase-fd 0, every interactive sudo-friendly CLI expects this.

The resulting CommandExecutionError then leaks through three channels:

  • minion logCommandExecutionError is logged at error level by the calling state / runner.
  • master log — in many invocation modes the error is forwarded back to the master and logged there too.
  • event-bus return datasalt-api and salt-run callers see the full message in the job return, so any user with cmd.run access via eauth can read another user's env-passed secrets just by mistyping the binary name.

ENOENT is not a rare condition. A typo in a binary path, a missing package on a particular minion, an os.execvp-style PATH miss — anything triggers it. A typo should not exfiltrate credentials.

This is the textbook anti-pattern in OWASP A09:2021 (Security Logging and Monitoring Failures) / CWE-532 (Insertion of Sensitive Information into Log File).

Setup

  • on-prem machine
  • container
  • classic packaging
  • onedir packaging

Affects every Salt deployment. cmd.run is one of the most-used execution modules and is invoked from a large fraction of states.

Steps to Reproduce the behavior

# Trigger an OSError by pointing cmd.run at a binary that does not
# exist, while passing a credential through env (a documented
# pattern). The CommandExecutionError raised will contain the
# credential value.
salt-call cmd.run /no/such/binary env='{"DB_PASSWORD": "leak-me-into-the-log"}'

Then look at the minion log: the credential value is right there in the error message. Same applies to stdin="..." — the stdin payload is dumped verbatim.

Expected behavior

The error message should retain the debugging context that is actually useful (the command, cwd, shell, executable, timeout) and should not include env or stdin, both of which contain user-supplied data that routinely includes credentials.

Versions Report

Type of salt install

Official deb

Major version

3006.x, 3007.x

What supported OS are you seeing the problem on? Can select multiple. (If bug appears on an unsupported OS, please open a GitHub Discussion instead)

debian-11, debian-12

salt --versions-report output

salt --versions-report
Salt Version:
          Salt: 3007.13

Python Version:
        Python: 3.10.19 (main, Feb  5 2026, 07:05:38) [GCC 11.2.0]

Dependency Versions:
          cffi: 2.0.0
      cherrypy: unknown
  cryptography: 42.0.5
      dateutil: 2.8.2
     docker-py: Not Installed
         gitdb: Not Installed
     gitpython: Not Installed
        Jinja2: 3.1.6
       libgit2: 1.9.1
  looseversion: 1.3.0
      M2Crypto: Not Installed
          Mako: Not Installed
       msgpack: 1.0.7
  msgpack-pure: Not Installed
  mysql-python: Not Installed
     packaging: 24.0
     pycparser: 2.21
      pycrypto: Not Installed
  pycryptodome: 3.19.1
        pygit2: 1.18.2
  python-gnupg: 0.5.2
        PyYAML: 6.0.1
         PyZMQ: 25.1.2
        relenv: 0.22.3
         smmap: Not Installed
       timelib: 0.3.0
       Tornado: 6.5.4
           ZMQ: 4.3.4

Salt Extensions:
 saltext.vault: 1.5.0

Salt Package Information:
  Package Type: onedir

System Versions:
          dist: debian 12.13 bookworm
        locale: utf-8
       machine: x86_64
       release: 6.12.73+deb12-amd64
        system: Linux
       version: Debian GNU/Linux 12.13 bookworm

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugbroken, incorrect, or confusing behaviorneeds-triage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions