A flaw was found in the automation-controller input-validation
guard sanitize_jinja(). The function uses two regular
expressions to reject user-supplied Jinja, but the patterns
stop at the first interior '}' or '%' character, so a Jinja
expression containing an inner brace (for example an empty
dict) is accepted while remaining valid Jinja. Because
sanitize_jinja() is the sole guard on several launch-time
fields — ad-hoc command module_args, Machine-credential
username / become_method / become_user, and inventory host
names — a low-privileged user can inject Jinja that ansible-core
evaluates in the execution environment. This enables execution
of arbitrary commands in the execution environment (bypassing an
administrator's AD_HOC_COMMANDS module allowlist) and disclosure
of secrets belonging to credentials the attacker cannot read
(by templating a co-attached credential's injected environment
variables), across the credential access-control boundary.
A template-injection flaw was found in the automation-controller. The
controller relies on a single helper, sanitize_jinja(), to reject
user-supplied Jinja in several fields that are later handed to ansible-core for
templating: the module arguments of ad-hoc commands, the username and
privilege-escalation fields of Machine credentials, and inventory host names.
That helper detects Jinja with two regular expressions whose negated character
classes stop at the first interior '}' or '%' character. As a result, a Jinja
expression that contains an inner brace — for example "{{ {} or
lookup('pipe','id') }}" — is not matched and is accepted, even though it is
fully valid Jinja that ansible-core will evaluate at task time. A
low-privileged user can therefore inject Jinja that runs inside the execution
environment. Two consequences are significant. First, the bypass defeats an
administrator who has restricted the allowed ad-hoc modules to non-executing
ones (such as ping) to provide "safe" ad-hoc access: a lookup('pipe', ...)
embedded in the ping module's arguments executes an arbitrary shell command in
the execution environment and returns its output in the job results. Second,
the bypass lets a user who administers Machine credentials, but who cannot read
another credential (such as a cloud or vault credential), place a
lookup('env', ...) expression in a credential field; when both credentials are
used together on a job template, the co-attached credential's secret is
injected into the execution environment's process environment, templated into
the attacker-controlled field, and surfaced in the job output — disclosing the
secret across the credential access-control boundary. The underlying weakness
is that the guard is an incomplete pattern-based blocklist rather than a real
Jinja lexer or an unambiguous rejection of any '{{' or '{%' sequence.
This issue has been addressed in the following products:
Red Hat Ansible Automation Platform 2.6 for RHEL 10
Red Hat Ansible Automation Platform 2.6 for RHEL 9
Via RHSA-2026:71113 https://access.redhat.com/errata/RHSA-2026:71113
This issue has been addressed in the following products:
Red Hat Ansible Automation Platform 2.5 for RHEL 9
Red Hat Ansible Automation Platform 2.5 for RHEL 8
Via RHSA-2026:71114 https://access.redhat.com/errata/RHSA-2026:71114
A template-injection flaw was found in the automation-controller. The controller relies on a single helper, sanitize_jinja(), to reject user-supplied Jinja in several fields that are later handed to ansible-core for templating: the module arguments of ad-hoc commands, the username and privilege-escalation fields of Machine credentials, and inventory host names. That helper detects Jinja with two regular expressions whose negated character classes stop at the first interior '}' or '%' character. As a result, a Jinja expression that contains an inner brace — for example "{{ {} or lookup('pipe','id') }}" — is not matched and is accepted, even though it is fully valid Jinja that ansible-core will evaluate at task time. A low-privileged user can therefore inject Jinja that runs inside the execution environment. Two consequences are significant. First, the bypass defeats an administrator who has restricted the allowed ad-hoc modules to non-executing ones (such as ping) to provide "safe" ad-hoc access: a lookup('pipe', ...) embedded in the ping module's arguments executes an arbitrary shell command in the execution environment and returns its output in the job results. Second, the bypass lets a user who administers Machine credentials, but who cannot read another credential (such as a cloud or vault credential), place a lookup('env', ...) expression in a credential field; when both credentials are used together on a job template, the co-attached credential's secret is injected into the execution environment's process environment, templated into the attacker-controlled field, and surfaced in the job output — disclosing the secret across the credential access-control boundary. The underlying weakness is that the guard is an incomplete pattern-based blocklist rather than a real Jinja lexer or an unambiguous rejection of any '{{' or '{%' sequence.