CVE-2026-84706: Automation-controller: automation-controller-container: automation-controller: credential type env-injector deny-list omits process-hijacking variables (bash_env/ld_preload) allowing code execution in the execution environment
A flaw was found in Ansible Automation Platform's automation-controller. Custom Credential Types let an author define injectors.env (environment variables set in the execution environment when a credential of that type is attached to a job) and injectors.file (files rendered into the execution environment whose path is exposed to other injectors as {{ tower.filename }}). The env-variable names are validated only by a deny-list: CredentialTypeInjectorField.validateenvvarallowed (awx/main/fields.py:689-701) rejects names beginning with "ANSIBLE" and names present in the ENVBLOCKLIST frozenset (awx/main/constants.py:48-70). The stated purpose of this control is to stop injectors from hijacking the runner process (it blocks PATH, PYTHONPATH, VIRTUALENV and all ANSIBLE configuration variables). The deny-list is incomplete: it does not include BASHENV, ENV, LDPRELOAD, LDLIBRARYPATH, LDAUDIT, PYTHONSTARTUP, PYTHONWARNINGS, GITSSHCOMMAND, PERL5OPT, or similar loader/ process-hijacking variables, so those names pass validation. An attacker can therefore define a credential type whose file injector writes a shell script and whose env injector sets BASHENV to {{ tower.filename }}. Every non-interactive bash process spawned during a job (Ansible modules shell out constantly) then sources and executes the attacker's script, yielding arbitrary code execution inside the execution-environment container — independent of the playbook content — for any job that attaches a credential of the malicious type, with access to the secrets of all co-attached credentials in the same job environment and to any inventory host the job can reach. The same weak check is repeated at the runtime injection sink (awxplugins.interfaces temporaryprivateinjectapi.py, which re-checks only ENVBLOCKLIST), so the fix must be applied in both places. Creating a custom credential type requires Controller superuser (CredentialTypeAccess inherits BaseAccess), so this is primarily a defense-in-depth bypass of a control whose explicit purpose is to constrain exactly this behavior; however, an organization-level Credential Admin (not a superuser) can weaponize an already-existing malicious custom type, and in Gateway-managed AAP 2.5+ the platform-admin role is explicitly not host/EE root, so code execution in the execution environment via a configuration API crosses a real trust boundary.
Upstream: https://github.com/ansible/tower (private) / awxplugins.interfaces Affected files: awx/main/fields.py:689-701; awx/main/constants.py:48-70; awxplugins/interfaces/temporaryprivateinjectapi.py:263-288
Other sources
A flaw was found in Ansible Automation Platform's automation-controller. The custom Credential Type environment-variable injector validates variable names against a deny-list (an ANSIBLE prefix check plus a fixed ENVBLOCKLIST) that omits process-hijacking loader variables such as BASHENV, ENV, LDPRELOAD, LDLIBRARYPATH, PYTHONSTARTUP and GITSSHCOMMAND. Combined with the credential file injector, a privileged user can write an attacker-controlled script into the execution environment and point BASHENV at it, obtaining arbitrary code execution inside the execution-environment container for any job that attaches a credential of that type.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Configuration
Extend the deny-list to block BASH_ENV, ENV, LD_PRELOAD, LD_LIBRARY_PATH, LD_AUDIT, PYTHONSTARTUP, PYTHONWARNINGS, GIT_SSH_COMMAND, and PERL5OPT, and apply the same validation in both CredentialTypeInjectorField.validate_env_var_allowed and awx_plugins/interfaces/_temporary_private_inject_api.py.
Ansible Automation Platform automation-controller credential type environment-variable injector ENV_BLOCKLIST and runtime environment-variable validation = BASH_ENV, ENV, LD_PRELOAD, LD_LIBRARY_PATH, LD_AUDIT, PYTHONSTARTUP, PYTHONWARNINGS, GIT_SSH_COMMAND, PERL5OPT
Event History
Frequently Asked Questions
What access does an attacker need to exploit this issue?
The attacker needs high privileges and the ability to define a custom Credential Type. Exploitation does not require user interaction and can be performed remotely.
Which jobs are exposed to the injected code?
A job is exposed when it runs with a credential of the attacker-defined type attached. The credential type can place a rendered script in the execution environment and set an allowed process-hijacking environment variable that causes the script to run.
What is the likely impact after successful exploitation?
The attacker can achieve code execution in the execution environment. The reported impact includes high integrity impact and low confidentiality impact, with no reported availability impact.