CVE-2025-20362 was published by Cisco on 25 September 2025 as advisory cisco-sa-asaftd-webvpn-YROOTUW. The bug is a missing-authorization fault in the VPN web server of Cisco Secure Firewall ASA and Cisco Secure Firewall Threat Defense; an unauthenticated remote attacker reaches restricted URL endpoints that the WebVPN handler should gate behind login. CISA added the entry to the Known Exploited Vulnerabilities Catalog the same week. On 5 November 2025 Cisco updated the advisory with a new in-the-wild attack variant that crashes unpatched devices, escalating the bug from credential exposure to denial of service. Two-hundred-thirty-three days after the advisory, the most recent public GitHub repository carrying the CVE number was created. It calls itself a safe scanner. The detection threshold for its HIGH RISK verdict fires on every Cisco WebVPN appliance that answers the door, patched or not.
CVE-2025-20362: The Scanner Flags Every Cisco WebVPN That Serves Its Logon Page
pattern
cve
proof of concept
The scanner sends one hundred and thirty requests. The first three reach the alarm.
The script's core is a doubly nested loop:
sensitive_paths = [
"/+CSCOE+/portal.html",
"/+CSCOE+/logon.html",
"/+CSCOE+/sessions.html", # Active sessions (very sensitive)
"/+CSCOE+/files/file_list.html", # File listing
"/+CSCOE+/files/file_action.html",
"/+CSCOE+/custom.html",
"/+CSCOE+/file.php",
"/+CSCOT+/session.html",
# Configuration / dump related (common in exploitation)
"/+CSCOE+/config",
"/+CSCOE+/running-config", # Sometimes exposed
"/+CSCOE+/showrunning",
"/+CSCOE+/download",
"/+CSCOE+/backup",
]
bypass_patterns = [
"",
"/..",
"/../",
"/+CSCOE+/../+CSCOE+/",
"/%2bCSCOE%2b/../%2bCSCOE%2b/",
"/+CSCOE+/..;/",
"/+CSCOE+/%2e%2e/",
"/+CSCOE+/%2e%2e%2f",
"/..%2f+CSCOE+/",
"/+CSCOU+/",
]Thirteen base paths, ten bypass patterns, one hundred and thirty constructed URLs per target. For each request the script reads status_code and len(text) and applies one test:
if status == 200 and length > 800:
lower_text = r.text.lower()
if any(kw in lower_text for kw in ["session", "webvpn", "config", "username", "password", "cscoe", "anyconnect", "running-config"]):
print(f" ⚠️ SENSITIVE CONTENT DETECTED!")
vulnerable_count += 1
sensitive_hits.append((test_url, status, length))Two responses meeting the test produce the final verdict:
if vulnerable_count >= 2:
print("\n🚨 HIGH RISK: Target appears VULNERABLE to CVE-2025-20362")
print(" Sensitive files / configuration data are accessible without authentication!")
print(" Immediate action required: Patch + investigate compromise.")The first entry in the bypass list is the empty string. With bypass = "", the constructed URL is base_url + base_path with nothing appended. No path traversal is attempted. The request is a direct fetch of the base path. The outer loop's first thirteen iterations are unmodified requests for the thirteen restricted paths the script considers sensitive.
Cisco's WebVPN ships /+CSCOE+/logon.html as the public-facing SSL VPN logon page. That page exists to be reached without authentication; the entire point of the URL is to render a form that AnyConnect or browser clients submit credentials through. The HTML body is several kilobytes. The body contains the strings webvpn, CSCOE, and AnyConnect because Cisco's portal references its own product names in form actions, JavaScript paths, and language-pack URLs. The script's keyword list, lowercased, matches each of those.
requests.get(..., allow_redirects=True) follows the redirects that ASA returns for authenticated-only paths. A request to /+CSCOE+/portal.html from an unauthenticated client lands on /+CSCOE+/logon.html. A request to /+CSCOE+/sessions.html from an unauthenticated client lands on /+CSCOE+/logon.html. The terminal body the script reads, in those redirect cases, is the logon page. The terminal status is 200. The terminal body length is above 800. The terminal text contains webvpn.
The first iteration of the outer loop that produces a 200 with the logon page in its body increments vulnerable_count to one. The second produces the threshold. The script prints the HIGH RISK banner. The next one hundred and twenty-eight requests are decoration; the verdict was set before any of the bypass patterns the README calls "the core of CVE-2025-20362" were exercised.
The detection signal is the product
The script flags every Cisco WebVPN appliance that serves its logon page as HIGH RISK for CVE-2025-20362, regardless of software version. A 9.20.4.7 box patched against the September 2025 advisory and current with the November 2025 follow-on fixes serves /+CSCOE+/logon.html for the same reason a 9.16.2 box does: because WebVPN is the SSL VPN portal product, and the logon page is the portal's entry point. The script cannot tell those two boxes apart. Its positive signal is reachability of the public portal, which is the precondition for using the product, not the consequence of the bug.
The keyword list does not narrow the test. webvpn, cscoe, anyconnect, session, config, username, password, running-config. These are the words Cisco's portal HTML contains by design. A patched appliance does not stop referencing its own product names in its public-facing pages. The script's threshold could in principle be set so that only bypassed responses (a successful traversal returning content from an authenticated endpoint with words like running-config in a configuration dump) would trigger. The threshold is not set that way. The threshold is two or more responses containing webvpn. Every WebVPN deployment meets it.
A defender running this scanner against a fleet of Cisco ASA appliances sees HIGH RISK on every appliance with WebVPN enabled. A defender running the scanner against a freshly-patched appliance to verify their work sees HIGH RISK. The verdict the script returns does not depend on whether the bypass succeeded. The verdict depends on whether the appliance answered the door.
What CVE-2025-20362 actually is
Cisco's advisory describes the bug as improper validation of user-supplied input in HTTP(S) requests against the WebVPN web server, leading to access of restricted URL endpoints that should be gated behind authentication. The CWE assignment on NVD is CWE-862, missing authorization. The CVSS vector is AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N: network-reachable, no privileges required, low confidentiality and integrity impact, no availability impact under the original vector.
The 5 November 2025 advisory update adds a separate exploitation primitive against the same input-validation gap: the gap can be coerced into crashing the device, escalating the impact past the original CVSS vector. The KEV entry's federal civilian remediation deadline lapsed in October 2025. The in-wild campaign chains CVE-2025-20362's missing-authorization with CVE-2025-20333's input-validation flaw in the same web server to reach root execution on the appliance. Cisco's continued-attacks resource documents the variant timeline; CISA, the UK NCSC, and Australian and Canadian government partners have published joint advisories about the cluster.
The mechanism the in-wild exploit uses is documented in those advisories at a level of detail Cisco's product disclosure deliberately stops short of reproducing in the CVE record itself. That mechanism is not what the curtishoughton scanner is testing. The ten bypass patterns the script ships, /.., /../, URL-encoded %2e%2e variants, ..;/, /+CSCOU+/, are the standard list of web-server path-traversal probes that appears in every introductory exploitation tutorial. Whether any of them maps to the specific normalization fault Cisco's patch closed is not asked; the script's HIGH RISK verdict has already fired on the logon page by the time the loop reaches them.
A third shape of CVE-shaped wrapper
We named the Placeholder PoC shape in the InSAT MasterSCADA case earlier this week: a script published under a CVE the publisher did not discover, structured as a working exploit, with the critical parameter explicitly admitted in a comment to be a guess. The publisher had no field name, so they wrote command and added # placeholder field next to it. The same week, the Cisco SD-WAN Bitcoin paywall case landed a sibling defect: a CVE-named repository that contained no exploit code at all, only a README pointing at a 0.00693 BTC SatoshiDisk listing. Different authors, different products, identical effect on the public exploit-availability surface: a CVE-shaped wrapper without the primitive inside.
The curtishoughton CVE-2025-20362 scanner is a third shape under the same Placeholder PoC name. The repository is not behind a paywall. The author's GitHub profile does not attempt portfolio inflation. The script is, in its README's framing, "a safe, non-destructive Python scanner" offered to defenders "to assess exposure on systems they are authorized to test." The defect is not a placeholder field admitted in a comment or an exploit hidden behind a payment link. The defect is in the detection threshold: the test that decides whether to print HIGH RISK is a test the product passes by existing.
The Placeholder PoC catalogue grows because the underlying incentive structure is stable. A CVE under remediation pressure (KEV listing, government joint advisory, recurring vendor updates) generates inbound search traffic on GitHub. Any repository whose name matches the CVE number receives that traffic. The repository's value to its author, whether the author is selling Bitcoin paywalls, building a personal brand, or sincerely trying to help defenders, depends only on the name matching. A scanner pipeline that registers "PoC available" on the existence of a CVE-named repository registers all three shapes identically. The InSAT script lacks a field. The Cisco SD-WAN repository lacks code. The curtishoughton scanner lacks a primitive the threshold could distinguish from the product. None of the three contain what a defender treating "PoC available" as actionable would assume they contain.
What the scanner promotes itself to do
The script's README closes with a section called "Vulnerability Details" that lists CVE-2025-20362's severity, type, affected products, and the chained CVE-2025-20333 RCE. The same README markets the artifact as a tool to assess WebVPN exposure on authorized systems. The script's terminal output, when run against any Cisco WebVPN appliance, is the eleven-line block beginning with 🚨 HIGH RISK: Target appears VULNERABLE to CVE-2025-20362 and ending with Immediate action required: Patch + investigate compromise.
A defender pasting that block into a ticketing system, a compliance report, or an executive summary is passing along an authority the script does not have. The script has the authority to confirm that the target appliance responded to HTTP requests with content that mentions webvpn. It does not have the authority to claim that the target is vulnerable to a specific CWE-862 normalization fault. The block conflates the two. Defenders working a CISA-deadline-driven patch queue without time to read the source of every CVE-named scanner they download from GitHub are exactly the audience that this output is most actionable against, and least useful for.
The two-hundred-thirty-three days between Cisco's advisory and this script's publication contain three vendor updates, an in-wild attack-variant disclosure, KEV inclusion, and joint government attribution to a specific threat actor cluster. None of that work is reproduced inside the script. What is inside the script is a list of paths every Cisco WebVPN appliance serves and a keyword list every Cisco WebVPN appliance's HTML contains.
The threshold is the product. The product is not the bug.