Command Injection

Detects potential command injection vulnerabilities in shell/command/raw tasks

27 rules in command_injection.yml

CRITICAL: 2 | HIGH: 19 | MEDIUM: 6

Rule IDSeverityTitleDescriptionRefs
docker_privileged_with_host_accessCRITICALDocker Privileged with Host AccessDocker command runs privileged container with host network access
raw_encoded_powershellCRITICALRaw Module with Encoded PowerShellUses Ansible raw module to execute base64-encoded PowerShell commands, hiding the actual payload
curl_with_credentialsHIGHCurl with Hardcoded CredentialsTask invokes curl/wget/HTTPie with hardcoded basic-auth credentials, a netrc file, or a -K config file containing user:password. The pair is visible in process listings and Ansible’s verbose output, defeating any vault elsewhere.
database_with_embedded_passwordHIGHDatabase Command with Embedded Passwordmysql/psql command embeds -p’’ on argv. The password appears in /proc//cmdline, in Ansible diff output, and in shell history; rotate and move to login_password parameters.
decode_pipe_to_shellHIGHDecode and Pipe to ShellTask decodes data and pipes to shell which is a common attack vector
download_pipe_to_shellHIGHDownload and Pipe to ShellTask pipes wget/curl output directly into bash/sh/zsh (curl ... | bash). The remote payload runs unverified and any MitM or compromised mirror executes attacker code as the playbook user.
eval_usageHIGHShell eval Builtin - Arbitrary Code Execution from a StringUses the shell eval builtin - which parses its argument as a shell command and executes it, collapsing the argv/shell distinction. The rule matches eval ONLY when it appears at the start of a shell command or immediately after a shell separator (;, &&, ||, \n, start of line). Splunk’s SPL | eval pipeline operator (splunk search '| eval host="*"'), MySQL’s eval(), and every other in-DSL eval are NOT the shell builtin and are NOT flagged.
interpreter_inline_code_executionHIGHInline Interpreter Payload Interpolates Jinja or Imports Exec-Family PrimitivesA shell / command / raw task invokes python / python3 / perl / ruby with -c / -e and an inline source string that is EITHER (a) interpolating a Jinja {{ var }} into the code - controller bytes are injected into live interpreter source at execution time - OR (b) imports one of the offensive-primitive modules os / subprocess / socket / pty / ctypes / Open3 / IO.popen (for ruby) / system / exec / backticks (for perl) AND calls an exec-family function. Pure literal inline code that doesn’t touch those primitives (python3 -c 'print(42)', perl -e 'print sort @ARGV') is a normal ops idiom and is NOT flagged.
password_in_command_lineHIGHPassword in Command LineTask passes -p’’ on the command line. Process listings and Ansible no_log defaults expose the password to anyone with host or log access.
powershell_encoded_commandHIGHPowerShell Encoded CommandTask uses PowerShell with encoded command which can hide malicious code
process_substitutionHIGHProcess SubstitutionShell/command/raw task uses Bash process substitution <(...) to inline a command’s output. Process substitution executes arbitrary subshells and is a common command-injection sink.
secret_var_in_command_argvHIGHSecret-Shaped Shell Variable Interpolated Into Command ArgvA shell task interpolates a shell variable whose name suggests secret material into an argv-revealing flag (-p, –patch, –data, –from-literal, –password, –token, –key, –secret-string, –set). Argv lands in /proc//cmdline, ps output, shell history, and audit logs - readable by every local user regardless of the source file’s mode bits.
shell_inline_compound_commandHIGHInline Shell -c Payload Interpolates Jinja or Evals Remote ScriptA shell / command / raw task invokes sh -c / bash -c / zsh -c / ksh -c (or the Debian-default /bin/sh which resolves to dash) with an inline payload that is EITHER (a) interpolating a Jinja {{ var }} into the script body - controller-side bytes flowing into a re-parsing shell, classic injection shape - OR (b) eval-ing a remote script via "$(curl ...)" / wget ... - the canonical supply-chain one-liner exploited by install.sh typosquats and the ohmyzsh / nvm / rustup bootstrap pattern. Pure literal compound commands (bash -c 'mkdir -p /opt && cp ...') are a normal operator idiom and are NOT flagged. Container-exec shapes (podman exec <c> bash -c '...', docker exec, kubectl exec -- bash -c, nerdctl exec, lxc exec, incus exec, buildah run, chroot, nsenter) are also NOT flagged - those MUST use bash -c to run a compound command inside the target namespace.
shell_pipe_to_interpreterHIGHShell Pipe to InterpreterTask pipes output to shell interpreter which can lead to command injection
subshell_executionHIGHSubshell / Command Substitution Interpolates a Jinja VariableA shell/command/raw task uses $(...) or backticks and interpolates a Jinja {{ var }} into the substitution. If the rendered variable contains shell metachars the substitution becomes an injection primitive (the inner shell re-parses the value, so even | quote on the outer command doesn’t protect the inner context). Plain command substitution WITHOUT a Jinja interpolation is a normal shell idiom ($(sha512sum file), $(basename $(dirname "$f"))) and is NOT flagged.
systemctl_with_user_inputHIGHSystemctl with User InputSystemctl command uses template variables which may be unsafe
user_input_executionHIGHDirect User Input ExecutionTask directly executes user input which is extremely dangerous
wget_pipe_to_shell_injectionHIGHWget Pipe to ShellTask downloads content and pipes to shell which is dangerous
windows_cmd_with_c_flagHIGHWindows CMD with /c Flagwin_shell or win_command task explicitly invokes cmd.exe /c, which evaluates the rest of the line via the legacy Windows command interpreter and reintroduces cmd metacharacter parsing.
windows_command_chainingHIGHWindows Command Chainingwin_shell or win_command task chains commands with ;, &&, or || in the same string. Chaining prevents Ansible from reasoning about return codes and lets a follow-on command run after a failure.
windows_shell_pipe_to_iexHIGHWindows Shell Pipe to Invoke-ExpressionWindows task pipes output to Invoke-Expression which can execute arbitrary code
command_chainingMEDIUMCommand Chaining with Template InterpolationA shell: or raw: task chains commands with ; / && / || AND interpolates a Jinja variable into the chain. If the variable renders to a value containing shell metachars, the chain becomes an injection surface (e.g. rm -rf /tmp/{{ name }} && restart) - an attacker-controlled name of ;; curl http://evil lets the chain pivot. Pure command chaining without interpolation is a normal automation idiom (podman stop foo || true, mkdir -p /opt/app && cd /opt/app && ./setup.sh) and is NOT flagged. command: is EXCLUDED because it does execve(argv[]) - ; / && / || become literal argv tokens and are never interpreted by a shell.
curl_with_multiple_variablesMEDIUMCurl with Multiple Template VariablesTask uses curl with multiple template variables which may be unsafe
environment_variable_executionMEDIUMShell Task References Attacker-Influenced Environment VariableA shell / command / raw task dereferences an environment variable (${VAR} / $VAR) whose name matches a well-known attacker-influenced source: CGI / reverse-proxy request headers (HTTP_*, QUERY_STRING, REQUEST_METHOD, REQUEST_URI, PATH_INFO, REMOTE_ADDR, REMOTE_USER), SSH forced-command inputs (SSH_ORIGINAL_COMMAND, SSH_CONNECTION), or sudo-preserved pass-through (SUDO_COMMAND). These values land inside the shell command unquoted, giving an attacker who controls the HTTP request / SSH key / sudo invocation arbitrary command execution. Locally-scoped shell loop variables (${name}, ${i}, ${f}) are NOT flagged - they are set earlier in the same shell body and are not attacker-influenced.
heredoc_with_variablesMEDIUMHeredoc with Template VariablesTask uses heredoc with template variables which may be unsafe
indirect_expansionMEDIUMIndirect Variable ExpansionTask uses indirect variable expansion which can be dangerous
secret_piped_to_text_processorMEDIUMSecret Manager Output Piped Through External Text ProcessorA shell task fetches material from a secret store (aws secretsmanager get-secret-value, gcloud secrets versions access, az keyvault secret show, vault kv get, op read, bw get password) and pipes the result through jq, awk, sed, grep, cut, or tr. Even with no_log: true, the secret crosses argv and process memory of every command in the pipe; auditd execve records, bash -x, set -x, and strace -f all capture the value. Use the corresponding lookup plugin or query syntax built into the CLI so the value never leaves the privileged process.