CVE-2026-71464
Executive Summary
CVE-2026-71464 is an argument-injection validation gap (CWE-88) in the LaunchConfigurationBaseSerializer.scm_branch field of an Ansible automation controller (AWX/Tower-class) web application. Unlike the Project, JobTemplate, and JobLaunch serializers, the launch-configuration serializer performs no leading-dash validation on scm_branch, allowing API clients with the ability to create a Schedule or a WFJT Node to submit values such as --upload-pack=/bin/id. The dangerous value is presently neutralized at task execution time by a runtime ValueError check in jobs.py:1502, so exploitation as remote code execution is not currently achievable — the defect is a missing defense-in-depth layer whose removal during refactoring would promote the issue to full RCE. CVSS v3.1 scores this 3.1 (Low), reflecting high attack complexity, low privilege requirement, and limited integrity impact.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Technical Analysis
The vulnerability class here is argument injection (CWE-88, "Improper Neutralization of Argument Delimiters in a Command"), a subtype of OS command injection in which an attacker cannot alter which binary is executed but can append attacker-controlled command-line options to that binary's invocation.
The NVD description identifies the following components and behaviors:
- Sink field:
LaunchConfigurationBaseSerializer.scm_branch— the DRF-style serializer field that accepts a source-control branch name during launch-configuration creation. - The gap: this serializer lacks a
validate_scm_branch()leading-dash check. By contrast, theProject,JobTemplate, andJobLaunchserializers do implement that validation. The defect is therefore an inconsistency between serializer classes rather than an absent control across the product. - Attack surface / inputs: a
Scheduleand aWFJT Nodeboth accept thescm_branchvalue — meaning two distinct API object types can carry the unvalidated payload into persistence. - Payload shape:
--upload-pack=/bin/id. This is a Git transport option.git's smart-transport client accepts--upload-pack=<program>to override the remote-side command executed over SSH. If an attacker-controlledscm_branchstring is inserted into agitcommand line without a--end-of-options delimiter, the string is parsed bygitas an option rather than a branch/tree-ish name. The--upload-pack=/bin/idvalue would cause the transport to invoke/bin/idin place of the pack negotiation program — command execution in the context of the controller worker process. - Current mitigation:
jobs.py:1502contains aValueErrorcheck that rejects the value at runtime. The description explicitly labels this "defense-in-depth" and states that the API validation gap means "sole reliance on a task-layer guard." The report's authors note that "refactoring that guard away would promote this to RCE."
Two important accuracy caveats apply:
- No public proof-of-concept, exploit code, or Nuclei template exists for this CVE. The attack chain below is inferred from the vulnerability class and from the specific artifacts named in the description.
- No affected version range, vendor advisory, or package identifier was supplied. It cannot be stated which released versions of the controller contain the unpatched serializer.
The core structural weakness is layering failure: input validation is duplicated across four sibling serializers, and one of them was omitted. Any future refactor, test-suite change, or accidental deletion of the jobs.py:1502 guard silently removes the final control and converts a Low-severity validation bug into a High/Critical authenticated RCE.
Exploitation Scenarios
No public PoC available; attack chain is inferred from vulnerability class and the artifacts named in the NVD description. Step-level details below remain at the class level where the description provides no specifics.
1) Reconnaissance / target identification.
An attacker identifies an automation controller web UI/API (AWX/Tower-class) exposed to their network position and confirms they hold an authenticated account with permission to create launch configurations — i.e., to define Schedule objects or WFJT Node entries. This is a low-privilege requirement consistent with the CVSS PR:L subscore. Reconnaissance is API-driven: enumerate the launch-configuration endpoints and confirm the scm_branch field is writable on the objects the account can create.
2) Triggering the flaw class.
The attacker submits a scm_branch value whose first character is -, specifically --upload-pack=/bin/id, when creating or updating a Schedule or WFJT Node. Because LaunchConfigurationBaseSerializer has no leading-dash check, the value passes serializer validation and is persisted — unlike the equivalent submission to a Project, JobTemplate, or JobLaunch serializer, which would be rejected by that serializer's validate_scm_branch().
3) Payload / execution method.
At the class level: when a job or schedule fires and the controller constructs a source-control command using the stored branch value, the leading --upload-pack=... token is interpreted by the git client as an option rather than a ref name. Absent a -- option terminator in the constructed command line, this causes the nominated program (/bin/id) to be invoked by the transport instead of the normal pack negotiation binary. The attacker does not need to break out of shell quoting; they are injecting a legitimate option with an attacker-chosen operand — the defining characteristic of CWE-88.
4) Post-execution impact — and why it is bounded today.
The jobs.py:1502 ValueError check intercepts the value during job execution, so the injected transport option is never handed to git in a vulnerable invocation. The observable outcome of a successful submission is therefore a rejected/failed job run, not code execution. Real impact under current code is limited to storing an invalid, attacker-chosen branch identifier — an integrity issue, matching the CVSS I:L subscore. The severity escalates to remote code execution only if the jobs.py:1502 guard is removed, refactored away, or bypassed. Post-exploitation in that hypothetical case would mean arbitrary command execution as the controller's worker user, with access to stored credentials, job artifacts, and connected managed hosts.
Impact Assessment
CVSS v3.1 base score 3.1 (Low), vector CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N:
- AV:N — the vulnerable interface is the network-exposed controller API.
- AC:H — high complexity: exploitation depends on additional conditions beyond the attacker's control. The description identifies one such condition explicitly — the runtime
jobs.py:1502guard — and a second implied one: the eventual construction of agitcommand line that lacks an option terminator and incorporates the stored branch value. - PR:L — low privileges required; the attacker needs an authenticated identity permitted to create a
ScheduleorWFJT Node. - UI:N — no user interaction.
- S:U — impact is scoped to the controller application.
- C:N — no confidentiality impact as currently scored, because the runtime guard prevents payload execution.
- I:L — limited integrity impact: invalid branch values can be persisted via
ScheduleandWFJT Nodeobjects. - A:N — no availability impact.
Affected systems: Ansible automation controller deployments (AWX/Tower-class) exposing the launch-configuration API. Exact version range unknown from the supplied data.
Blast radius: Currently narrow — authenticated API users with schedule/workflow-node creation rights, and only the ability to store malformed branch identifiers. The latent blast radius is large: automation controllers hold SSH credentials, vault secrets, and inventory access for managed estate. Should the jobs.py:1502 defense-in-depth guard be refactored away, the same primitive yields authenticated RCE with the controller's privileges, and lateral movement to managed nodes becomes feasible.
Scoring note: no EPSS score has been published by FIRST.org for this CVE at time of writing, and no EPSS value should be inferred. The CVE is not listed in CISA KEV, and there is no evidence of exploit-in-the-wild activity.
Detection Guidance
Detection focuses on (a) leading-dash scm_branch values arriving at the launch-configuration API, (b) --upload-pack or similar git transport options appearing in stored branch metadata, and (c) the ValueError guard firing in controller logs.
Sigma Rule
title: Ansible Controller scm_branch Leading-Dash Argument Injection (CVE-2026-71464)
id: 7f3c1b90-2a44-4e8d-9c11-6a5d0e714c64
status: experimental
description: >
Detects API requests submitting a leading-dash scm_branch value to launch
configuration endpoints (Schedule / WFJT Node), exploiting the missing
validate_scm_branch() check in LaunchConfigurationBaseSerializer (CVE-2026-71464).
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-71464
author: valtersit.com
date: 2026/01/01
tags:
- attack.t1059
- attack.initial_access
logsource:
category: webserver
product: awx
detection:
selection_method:
cs-method:
- 'POST'
- 'PUT'
- 'PATCH'
selection_path:
cs-uri-stem|contains:
- '/schedules/'
- '/workflow_job_nodes/'
- '/workflow_job_template_nodes/'
- '/launch_configurations/'
selection_payload:
- cs-uri-query|contains: 'scm_branch=--'
- cs-uri-query|contains: 'scm_branch=%2D%2D'
- request_body|contains: '"scm_branch": "--'
- request_body|contains: '"scm_branch":"--'
condition: selection_method and (selection_path or selection_payload)
falsepositives:
- Legitimate branch names beginning with a hyphen (extremely rare; should be rejected anyway)
level: high
YARA Rule
rule CVE_2026_71464_scm_branch_arg_injection
{
meta:
description = "Detects leading-dash scm_branch argument injection payloads and the controller launch serializer artifact for CVE-2026-71464"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2026-71464"
author = "valtersit.com"
date = "2026-01-01"
cwe = "CWE-88"
severity = "low"
strings:
$scm1 = "scm_branch" ascii wide nocase
$scm2 = "LaunchConfigurationBaseSerializer" ascii wide
$opt1 = "--upload-pack=" ascii wide nocase
$opt2 = "--upload-pack" ascii wide nocase
$opt3 = "--receive-pack=" ascii wide nocase
$opt4 = "--exec=" ascii wide nocase
$dash = "scm_branch\": \"--" ascii
$json = "\"scm_branch\":\"--" ascii
$vlerr = "ValueError" ascii wide
condition:
(uint16(0) == 0x7B7B or uint16(0) == 0x3C3F or true) and
(
any of ($opt1, $opt2, $opt3, $opt4) and $scm1
or any of ($dash, $json)
or ($scm2 and $scm1)
)
}
Suricata IDS Rule
alert http any any -> any any (msg:"CVE-2026-71464 Ansible Controller scm_branch Leading-Dash Argument Injection Attempt"; flow:established,to_server; http.method; content:"POST"; http.method; content:"PATCH"; http.method; content:"PUT"; http.uri; content:"scm_branch"; http.request_body; content:"scm_branch"; nocase; http.request_body; content:"--upload-pack="; nocase; http.request_body; content:"--upload-pack"; nocase; http.request_body; pcre:"/scm_branch\\?["':\\s=]+(?:\"|%22)?--[a-zA-Z]/i"; classtype:attempted-admin; reference:cve,2026-71464; reference:url,www.valtersit.com; metadata:service http; sid:202671464; rev:1;)
alert http any any -> any any (msg:"CVE-2026-71464 Ansible scm_branch encoded leading-dash payload"; flow:established,to_server; http.uri; content:"scm_branch="; nocase; http.uri; pcre:"/scm_branch=(?:%2D%2D|--)[A-Za-z0-9_-]/i"; classtype:attempted-admin; reference:cve,2026-71464; sid:202671465; rev:1;)
Elastic Detection
sequence by user.name, source.ip with maxspan=5m
[ network where event.action == "http_request"
and http.request.method in ("POST", "PUT", "PATCH")
and (
wildcard(http.request.body, "*\"scm_branch\": \"--*")
or wildcard(http.request.body, "*\"scm_branch\":\"--*")
or wildcard(url.query, "scm_branch=--*")
or wildcard(url.query, "scm_branch=%2D%2D*")
or wildcard(http.request.body, "*--upload-pack*")
) ]
[ any where true ]
A complementary event-based variant for controller application logs:
any where event.category == "application" and
(wildcard(message, "*jobs.py:1502*") or wildcard(message, "*ValueError*")) and
wildcard(message, "*scm_branch*")
Splunk SPL Query
index=web OR index=awx sourcetype IN ("access_combined","awx:api","json_web")
(method IN ("POST","PUT","PATCH"))
(uri_path="*schedules*" OR uri_path="*workflow_job_nodes*" OR uri_path="*launch_configurations*" OR uri="*scm_branch*")
(uri_query="*scm_branch=--*" OR uri_query="*scm_branch=%2D%2D*" OR body="*\"scm_branch\": \"--*" OR body="*--upload-pack*" OR body="*--receive-pack*")
| eval risk="CVE-2026-71464 argument injection attempt"
| stats count min(_time) as first_seen max(_time) as last_seen values(uri) as uris by src_ip, user, risk
| where count >= 1
| sort - count
Correlate with the runtime guard firing (defense-in-depth check in jobs.py:1502):
index=awx sourcetype="awx:*"
("jobs.py:1502" OR "scm_branch" AND "ValueError")
| stats count by host, job_id, user, message
| sort - count
Wazuh OSSEC Rule
<group name="web,ansible,awx,cve-2026-71464,">
<rule id="2026714" level="10">
<decoded_as>json</decoded_as>
<field name="method">POST|PUT|PATCH</field>
<field name="url">scm_branch=--|scm_branch=%2D%2D</field>
<description>CVE-2026-71464: Possible scm_branch leading-dash argument injection against Ansible controller API</description>
<mitre>
<id>T1059</id>
</mitre>
<group>attack,arg_injection,</group>
</rule>
<rule id="2026715" level="10">
<decoded_as>json</decoded_as>
<field name="body">--upload-pack|--receive-pack|scm_branch\": \"--</field>
<description>CVE-2026-71464: Git transport option injected via scm_branch field</description>
<mitre>
<id>T1059</id>
</mitre>
<group>attack,arg_injection,</group>
</rule>
<rule id="2026716" level="7">
<decoded_as>syslog</decoded_as>
<match>jobs.py:1502</match>
<match>scm_branch</match>
<description>CVE-2026-71464 defense-in-depth guard triggered: ValueError rejecting scm_branch at job layer</description>
<group>ansible,awx,guard_triggered,</group>
</rule>
</group>
Mitigation & Patch Guidance
Patch confidence: 2/4 (CLAIMED — single source claims patch, not independently confirmed). The only patch source is NVD; no vendor advisory, commit hash, or version identifier was supplied. Treat the patch as unverified until confirmed against a vendor-published release note or the upstream repository.
1) Immediate mitigations (compensating controls, apply now):
- Do not rely on the runtime guard alone. The
jobs.py:1502ValueErrorcheck is the sole remaining control; any change to job execution code removes it. Treat it as a tripwire, not a fix. - Enforce leading-dash rejection at the front door: place a reverse proxy or API gateway in front of the controller that rejects any request body or query parameter containing
scm_branchwith a value beginning with-or%2D. Deploy the Suricata and Wazuh rules above in blocking mode where policy permits. - Restrict API write permissions: audit which accounts and service tokens can create
ScheduleandWFJT Nodeobjects, and reduce that set to the minimum. Because the CVSS vector specifiesPR:L, every unnecessary low-privilege principal with these rights is an expanded attack surface. - Alert on all
jobs.py:1502guard hits. Each occurrence is a concrete signal that someone attempted to store a leading-dash branch value — that is a deliberate act, not a user error. - Keep the controller API off untrusted networks; require authentication and, where feasible, mTLS for automation API consumers.
2) Patch / upgrade steps:
- Monitor the upstream Ansible/AWX release channel and the NVD entry for a confirmed fixed version. No affected-range data was provided with this CVE, so do not assume a version is fixed based on the "CLAIMED" patch flag alone.
- When a fix is published, verify it by inspecting the serializer source:
LaunchConfigurationBaseSerializershould gain avalidate_scm_branch()method performing the same leading-dash rejection as theProject,JobTemplate, andJobLaunchserializers. An upgrade that does not add this validation does not resolve CVE-2026-71464. - Verify the
jobs.py:1502guard is still intact after upgrading; the fix should add a validation layer above it, not replace it. - Test in staging by submitting
scm_branch="--upload-pack=/bin/id"to both aScheduleand aWFJT Nodecreation endpoint and confirming rejection at the serializer layer, before the job executes.
3) Long-term hardening:
- Eliminate the duplicated-validation pattern that caused this defect: implement a shared
validate_scm_branch()mixin or base-class validator inherited by all serializers that accept an SCM branch, so no sibling class can silently omit the check. - Add regression tests that assert leading-dash rejection on every serializer exposing
scm_branch, and run them as a merge gate. Refactors must be unable to remove this coverage without failing CI. - Insert a
--end-of-options terminator into every constructedgitcommand line that incorporates user-controlled values, so hostile tokens are treated as refs, not options. This addresses the underlying CWE-88 condition independent of serializer validation. - Reduce the latent blast radius: run controller workers with least-privilege OS accounts, scope and rotate stored credentials, and isolate the worker process from privileged files and the host network.
- Maintain continuous monitoring of the controller logs for guard-layer
ValueErrorevents as an early-warning indicator of both exploitation attempts and future regressions in job-layer protection.
References
- NVD — CVE-2026-71464: https://nvd.nist.gov/vuln/detail/CVE-2026-71464
- MITRE CWE-88, Improper Neutralization of Argument Delimiters in a Command ("Argument Injection"): https://cwe.mitre.org/data/definitions/88.html
- MITRE ATT&CK T1059, Command and Scripting Interpreter: https://attack.mitre.org/techniques/T1059/
- Ansible AWX upstream project (see release notes and security advisories for confirmed fix status): https://github.com/ansible/awx
- CVSS v3.1 specification (score computation reference): https://www.first.org/cvss/v3.1/specification-document
Threat actor / exploit status: No public proof-of-concept, exploit code, or Nuclei template is known for CVE-2026-71464. No threat actor campaign, scanning activity, or exploit-in-the-wild evidence has been reported. The CVE is not listed in CISA KEV. EPSS has no published score from FIRST.org for this CVE; no estimate should be substituted. Because exploitation is currently blocked by a runtime guard, weaponization is unlikely until either the guard is removed in a future release or an additional bypass of jobs.py:1502 is discovered and published.
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.