Paramiko exec_command() Usage

MEDIUM

paramiko exec_command() runs commands on a remote host. Audit that command arguments are not derived from untrusted input to prevent command injection.

Rule Information

Language
Python
Category
Python Core
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonparamikosshexec-commandcommand-injectionCWE-78OWASP-A03
CWE References

Interactive Playground

Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.

pathfinder scan --ruleset python/PYTHON-LANG-SEC-072 --project .
1
2
3
4
5
6
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

About This Rule

Understanding the vulnerability and how it is detected

paramiko's SSHClient.exec_command() executes a shell command on the remote server via the SSH exec channel. The command is passed to the remote shell (/bin/sh by default) which interprets shell metacharacters. When the command string is constructed from untrusted user input, an attacker can inject shell metacharacters to execute additional commands on the remote host.

The risk pattern is the same as local OS command injection but the impact is remote: the injected commands execute on the SSH server with the SSH user's privileges on that system.

SSH exec_command() sends a single command to the remote shell without an interactive session. Use paramiko's invoke_shell() only when an interactive session is genuinely required, and use exec_command() with validated, sanitized arguments for automation.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Remote Command Injection

Shell metacharacters in user-controlled content injected into exec_command() execute additional commands on the remote SSH server. Semicolons, pipes, backticks, and dollar signs are all interpreted by the remote shell, enabling injection of arbitrary remote commands.

2

Remote System Compromise

Injected commands execute with the SSH user's privileges on the remote server. If the SSH user has sudo rights or the server runs other sensitive services, command injection can escalate to full remote system compromise.

3

Lateral Movement

SSH automation scripts that execute commands on multiple servers are particularly dangerous when compromised. Command injection in one server's exec_command() call can affect all servers in the automation pool.

4

Sensitive Output Capture

If the injected command outputs sensitive data (credentials, private keys, configuration) and stdout is captured, the attacker can extract this data through the command output returned to the Python application.

How to Fix

Recommended remediation steps

  • 1Validate all user-controlled values that appear in exec_command() arguments against strict allowlists or regex patterns before use.
  • 2Use shlex.quote() to properly quote arguments that must be included in shell commands executed via exec_command().
  • 3Prefer a fixed allowlist of pre-defined commands over dynamic command construction; store full commands as constants and look them up by validated name.
  • 4Capture and validate the exit code and stderr from exec_command() to detect errors and potential injection attempts.
  • 5Use SFTP for file operations instead of exec_command() with cp/mv/cat to eliminate shell involvement entirely.

Detection Scope

How Code Pathfinder analyzes your code for this vulnerability

This rule detects calls to exec_command() on paramiko SSHClient and Channel objects. All call sites are flagged since exec_command() executes commands on remote systems via a shell, and the command argument requires review to ensure no user-controlled content can inject shell metacharacters.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

CWE Top 25
CWE-78 ranked #5 in 2023 Most Dangerous Software Weaknesses
OWASP Top 10
A03:2021 - Injection
NIST SP 800-53
SI-10: Information Input Validation
PCI DSS v4.0
Requirement 6.2.4 - Protect against injection attacks

References

External resources and documentation

Similar Rules

Explore related security rules for Python

Frequently Asked Questions

Common questions about Paramiko exec_command() Usage

exec_command() sends an SSH "exec" request to the remote server, which is typically handled by the SSH server's shell (sshd runs the command via /bin/sh -c "command"). This means shell metacharacters in the command string are interpreted. Unlike subprocess.run() with a list, there is no equivalent shell-free mode for exec_command().
shlex.quote() wraps the argument in single quotes and escapes any internal single quotes, producing a shell-safe string. Using shlex.quote() on each user-supplied argument before including it in the command string prevents most shell injection. However, it does not protect against argument injection (flags starting with "-") or against choosing the command itself from user input.
paramiko's Transport and Channel API allows sending "exec" requests without shell interpretation in theory, but the SSH server-side daemon (sshd) typically still passes the command to a shell via -c. For truly shell-free execution, use SFTP for file operations or consider a dedicated protocol (gRPC, REST over SSH tunnel) for application commands.
exec_command() opens a new channel, runs a single command, and closes. It is non- interactive and suitable for automation. invoke_shell() opens an interactive terminal emulator session that persists until explicitly closed. exec_command() is preferred for automation; invoke_shell() has additional complexity and fewer use cases.
exec_command() returns immediately with stdin, stdout, stderr channels. For long- running commands, use stdout.channel.recv_exit_status() to wait for completion and check the exit code. Set a timeout using the get_transport().global_request_timeout or read with a timeout to prevent indefinite blocking.
Use SFTP (ssh.open_sftp()) for file operations such as reading, writing, listing directories, and transferring files. SFTP does not involve a shell and is not vulnerable to shell injection. Use exec_command() only when you need to run actual commands and cannot accomplish the task via SFTP.

New feature

Get these findings posted directly on your GitHub pull requests

The Paramiko exec_command() Usage rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works